質問

これに似たテーブルがあります。

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

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

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

アップデート: 私は posgreSQL を使用しているため、高度な MS-SQL 機能は利用できません。いずれにせよ、これは一般的な SQL の質問として扱われることを望みます。

ところで、質問してから 15 分以内に 6 件の回答が得られたことに非常に感銘を受けました。スタックオーバーフローに行きましょう!

役に立ちましたか?

解決

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);

他のヒント

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

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).

2番 select 返すものがなくなるまで、前の結果の子を繰り返し追跡します。

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

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

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

ジョー・セルコはこの作品の原作者です。 ネストされたセット SQL で階層を保存するアプローチ。Googleできます 「ネストされたセット」階層 背景をより深く理解するために。

または、parentid の名前を次のように変更することもできます 左端 そして追加します 右ID.

以下は、ネストされたセットを要約する私の試みですが、私は Joe Celko ではないので、ひどく不十分になるでしょう。SQL はセットベースの言語であり、隣接モデル (親 ID を保存する) はセットベースの階層表現ではありません。したがって、隣接関係スキーマをクエリするための純粋なセットベースの方法はありません。

しかし, 、主要なプラットフォームのほとんどは、この正確な問題に対処するために近年拡張機能を導入しました。したがって、誰かが Postgres 固有のソリューションについて返信した場合は、ぜひそれを使用してください。

再帰クエリを作成する標準的な方法 SQL 再帰的です CTE. 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)

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

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

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

ここに良いチュートリアルがあります:

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

使う 共通テーブル式.

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

ここに記事があります 共通のテーブル式を使用しない SqlTeam による再帰の場合。

次のコードはコンパイルされ、テストでは問題なく実行されます。

create or replace function subtree (bigint)
returns setof example as $$
declare
    results record;
    entry   record;
    recs    record;
begin
    select into results * from example where parent = $1;
    if found then
        for entry in select child from example where parent = $1 and child  parent loop
            for recs in select * from subtree(entry.child) loop
                return next recs;
            end loop;
        end loop;
    end if;
    return next results;
end;
$$ language 'plpgsql';

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

楽しむ :)

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

簡単な余談ですが、質問には非常によく答えられていますが、これを次のように扱うと注意が必要です。

一般的なSQLの質問

SQL'99 では仕様内で線形再帰が許可されているため (標準を完全に実装している RDBMS はないと思いますが)、SQL の実装は非常に簡単です。 WITH RECURSIVE 声明。したがって、理論的な観点からは、これを今すぐ行うことができます。

どの例も私にとってはうまく機能しなかったので、次のように修正しました。

declare
    results record;
    entry   record;
    recs    record;
begin
    for results in select * from project where pid = $1 loop
        return next results;
        for recs in select * from project_subtree(results.id) loop
            return next recs;
        end loop;
    end loop;
    return;
end;

これは SQL Server ですか?結果をループして結合する TSQL ストアド プロシージャを作成できないでしょうか?

SQL のみでこれを行う方法があるかどうかにも興味があります。地理データベースの授業で覚えている限りでは、あるはずです。

SQL 2008ではもっと簡単だと思います 階層ID

階層だけでなく任意のグラフを保存する必要がある場合は、Postgres を脇に置いて、次のようなグラフ データベースを試すことができます。 アレグログラフ:

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

Hibernate や Django ORM などとはうまく統合できませんが、(Nested Set モデルのような階層だけでなく) グラフ構造について真剣に考えている場合は、チェックしてみてください。

また、Oracle がついに最新製品に実際のグラフのサポートを追加したと私は信じていますが、これほど時間がかかったのには驚き、多くの問題がこのモデルから恩恵を受ける可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top