63

私はこれに似たテーブルを持っています:

CREATE TABLE example (
  id integer primary key,
  name char(200),
  parentid integer,
  value integer);

parentidフィールドを使用して、データをツリー構造に配置できます。

これが私が解決できないビットです。親IDが与えられた場合、その親IDの下にあるすべての値フィールドを合計し、ツリーのブランチを再帰的に実行するSQLステートメントを作成することは可能ですか?

更新:私はposgreSQLを使用しているので、派手なMS-SQL機能を利用できません。いずれにせよ、これを一般的なSQLの質問として扱いたいと思います。

ところで、私は質問をしてから15分以内に6つの答えがあることに非常に感銘を受けました!スタックオーバーフローに行きます!

4

14 に答える 14

42

共通テーブル式を使用したスクリプトの例を次に示します。

with recursive sumthis(id, val) as (
    select id, value
    from example
    where id = :selectedid
    union all
    select C.id, C.value
    from sumthis P
    inner join example C on P.id = C.parentid
)
select sum(val) from sumthis

上記のスクリプトは、 とsumthisという列を持つid「仮想」テーブルを作成しますval。これは、 でマージされた 2 つの選択の結果として定義されunion allます。

最初selectにルート ( where id = :selectedid) を取得します。

Secondselectは、返すものがなくなるまで、前の結果の子を繰り返したどります。

最終結果は、通常のテーブルのように処理できます。この場合、val 列が合計されます。

于 2011-04-18T09:50:16.330 に答える
34

バージョン 8.4 以降、PostgreSQL はSQL 標準構文を使用した共通テーブル式の再帰クエリをサポートしています。WITH

于 2009-02-14T06:39:39.873 に答える
15

ANSI SQL-92 RDBMS で動作するポータブル ソリューションが必要な場合は、テーブルに新しい列を追加する必要があります。

Joe Celko は、SQL に階層を格納するためのNested Setsアプローチの最初の作成者です。「ネストされたセット」階層をGoogleで検索すると、背景について詳しく理解できます。

または、parentidの名前を leftid に変更し、 rightidを追加することもできます。

ネストされたセットを要約する試みは次のとおりです。私は Joe Celko ではないため、非常に不十分です。SQL はセットベースの言語であり、隣接モデル (親 ID を格納する) は階層のセットベースの表現ではありません。したがって、隣接スキーマを照会する純粋なセットベースの方法はありません。

ただし、主要なプラットフォームのほとんどは、この正確な問題に対処するために、近年拡張機能を導入しています。したがって、誰かが Postgres 固有の解決策で返信した場合は、必ずそれを使用してください。

于 2008-09-09T23:40:43.020 に答える
12

PostgreSQL で必要なことを行うには、いくつかの方法があります。

このようなもの:

create or replace function example_subtree (integer)
returns setof example as
'declare results record;
         child record;
 begin
  select into results * from example where parent_id = $1;
  if found then
    return next results;
    for child in select id from example
                  where parent_id = $1
      loop
        for temp in select * from example_subtree(child.id)
        loop
          return next temp;
        end loop;
      end loop;
  end if;
  return null;
end;' language 'plpgsql';

select sum(value) as value_sum
  from example_subtree(1234);
于 2008-09-10T15:16:56.747 に答える
10

で再帰クエリを作成する標準的な方法SQLは recursiveCTEです。PostgreSQL以来、それらをサポートしてい8.4ます。

以前のバージョンでは、再帰的な集合を返す関数を書くことができました:

CREATE FUNCTION fn_hierarchy (parent INT)
RETURNS SETOF example
AS
$$
        SELECT  example
        FROM    example
        WHERE   id = $1
        UNION ALL
        SELECT  fn_hierarchy(id)
        FROM    example
        WHERE   parentid = $1
$$
LANGUAGE 'sql';

SELECT  *
FROM    fn_hierarchy(1)

この記事を参照してください。

于 2011-01-11T16:11:19.793 に答える
5

共通テーブル式を使用します。

これがSQLServer2005以降のみであることを示したい場合があります。デール・ラガン

これは、一般的なテーブル式を使用しないSqlTeamによる再帰に関する記事です。

于 2008-09-09T23:17:06.320 に答える
5

SQL Server 2005を使用している場合は、共通テーブル式を使用してこれを行うための非常に優れた方法があります。

これにより、一時テーブルの作成からすべての面倒な作業が不要になり、基本的に、WITHとUNIONだけですべてを実行できます。

これが良いチュートリアルです:

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

于 2008-09-09T23:23:59.597 に答える
2

次のコードはコンパイルされ、正常にテストされています。

関数サブツリーの作成または置換 (bigint)
例のセットを $$ として返します
宣言する
    結果記録;
    入国記録;
    レコードを記録します。
始める
    結果に選択 * 親 = $1 の例から。
    もし見つかったら
        親が $1 で、子が親ループの場合の例から子を選択するエントリの場合
            for recs in select * from subtree(entry.child) ループ
                次のレコードを返します。
            ループを終了します。
        ループを終了します。
    終了する場合;
    次の結果を返します。
終わり;
$$ 言語 'plpgsql';

私の場合、ノードは自分自身を指しているため、「子 <> 親」という条件が必要です。

楽しむ :)

于 2009-02-03T21:14:11.583 に答える
1

Oracleには「START WITH」と「CONNECT BY」があります

select 
    lpad(' ',2*(level-1)) || to_char(child) s

from 
    test_connect_by 

start with parent is null
connect by prior child = parent;

http://www.adp-gmbh.ch/ora/sql/connect_by.html

于 2008-09-09T23:30:11.330 に答える
1

どの例もうまくいかなかったので、次のように修正しました。

宣言する
    結果記録;
    入国記録;
    レコードを記録します。
始める
    for results in select * from project where pid = $1 ループ
        次の結果を返します。
        for recs in select * from project_subtree(results.id) ループ
            次のレコードを返します。
        ループを終了します。
    ループを終了します。
    戻る;
終わり;
于 2011-01-11T16:03:10.220 に答える
0

これはSQLServerですか?結果をループして結合するTSQLストアドプロシージャを記述できませんでしたか?

ただし、これを行うSQLのみの方法があるかどうかにも興味があります。私の地理データベースクラスから覚えているビットから、あるはずです。

于 2008-09-09T23:16:19.193 に答える
0

SQL2008ではHierarchyIDを使用する方が簡単だと思います

于 2008-09-09T23:23:47.757 に答える
-1

階層だけでなく任意のグラフを保存する必要がある場合は、Postgresを横に押して、AllegroGraphなどのグラフデータベースを試すことができます。

グラフデータベース内のすべてがトリプル(ソースノード、エッジ、ターゲットノード)として格納され、グラフ構造を操作し、SQLのような言語を使用してクエリするためのファーストクラスのサポートを提供します。

HibernateやDjangoORMのようなものとはうまく統合されませんが、グラフ構造(入れ子集合モデルのような階層だけでなく)に真剣に取り組んでいる場合は、それをチェックしてください。

また、オラクルが最終的に最新の製品に実際のグラフのサポートを追加したと思いますが、非常に時間がかかり、このモデルから多くの問題が恩恵を受ける可能性があることに驚いています。

于 2008-09-10T00:30:37.143 に答える