8

私は2つのテーブルを持っています。 itemsitemItems

itemItems間の多対多の関係について説明しitemsます。つまり、 のメンバーはitems多くの子を持つことができ、それらは多くの子供を持つことができ、さらに多くの子供を持つことができます。

アイテム:

itemID |  more stuff ......
1         ...    
2         ...
3         ...
4         ...

itemItems:

parentItemID |  childItemID  
1               2 
1               3
2               4

1 つのルート ノードの下にあるすべての子を再帰的に取得するクエリを作成したいと考えています。

これは再帰結合と呼ばれるもので可能だと思いますが、その概念は非常に紛らわしいと思います....(この質問に似ていますが、sqliteではなくsql serverで、多対多では1対多ではありません)

次のようにして、最初のレベル (つまり、1 つのアイテムの下にあるすべての子) を取得できます。

SELECT * 
FROM items 
INNER JOIN itemItems
ON items.itemID = itemItems.childItemID
WHERE itemItems.parentItemID = 1

これを拡張して、すべての子供の子供などを再帰的に取得するにはどうすればよいですか?

4

2 に答える 2

10

with recursive構文を使用して動作する同様のクエリを取得しました。一般的な形式は次のとおりです。

with recursive tc( i )
  as ( select [... initial-query ...]
        union [... recursive-part (include tc) ...]
     )
 select * from tc;

私の場合の鍵は、再帰部分に tc がリストされていることを確認することでした。また、この最後の選択は推移閉包の完全な内容を表示するためのものであり、実際の選択では必要な行を選択する必要があります。

このレシピは、次のようにあなたの場合に当てはまると思います。私はこれをテストしていません。クエリからコピー/貼り付けして、テーブル名に置き換えているだけです。それは私にとってはうまくいきますが、これを間違って翻訳した可能性があります。また、効率などについてもよくわかりません。

with recursive tc( i )
  as ( select childItemID from itemItems where parentItemID = 1
        union select childItemID from itemItems, tc
               where itemItems.parentItemID = tc.i
     )
  select * from item where itemID in tc;

注: これはバージョン 3.8.3.1 では機能しましたが、3.7.2 では機能しませんでした。

于 2014-03-07T14:58:20.013 に答える
1

上記の再帰バージョンには、当時の一般的な DBMS でサポートされている ANSI SQL:1999 が必要ですが、境界再帰を実現するための ANSI SQL-92 メソッドもあります。このアプローチは任意に拡張できます。

以下の例では、最大 7 つのレベルをサポートしています。もっと欲しい場合は、さらに追加してください。

SELECT DISTINCT
    I.*
FROM
    item I INNER JOIN (
        SELECT 
            I1.itemID as Level1,
            I2.itemID as Level2,
            I3.itemID as Level3,
            I4.itemID as Level4,
            I5.itemID as Level5,
            I6.itemID as Level6,
            I7.itemID as Level7
        FROM 
            item I1 LEFT JOIN 
            item I2 ON EXISTS (SELECT NULL FROM itemItems II1 WHERE II1.parentItemID = I1.itemID AND I2.itemID = II1.childItemID) LEFT JOIN
            item I3 ON EXISTS (SELECT NULL FROM itemItems II2 WHERE II2.parentItemID = I2.itemID AND I3.itemID = II2.childItemID) LEFT JOIN
            item I4 ON EXISTS (SELECT NULL FROM itemItems II3 WHERE II3.parentItemID = I3.itemID AND I4.itemID = II3.childItemID) LEFT JOIN
            item I5 ON EXISTS (SELECT NULL FROM itemItems II4 WHERE II4.parentItemID = I4.itemID AND I5.itemID = II4.childItemID) LEFT JOIN
            item I6 ON EXISTS (SELECT NULL FROM itemItems II5 WHERE II5.parentItemID = I5.itemID AND I6.itemID = II5.childItemID) LEFT JOIN
            item I7 ON EXISTS (SELECT NULL FROM itemItems II6 WHERE II6.parentItemID = I6.itemID AND I7.itemID = II6.childItemID)
        WHERE
            I1.itemID = 1    -- root node condition
    ) D ON I.itemID = D.Level1 OR I.itemID = D.Level2 OR I.itemID = D.Level3 OR I.itemID = D.Level4 OR I.itemID = D.Level5 OR I.itemID = D.Level6 Or I.itemID = D.Level7
于 2013-05-03T05:51:34.477 に答える