3

次の構造を持つメニュー システムのテーブルといくつかのデータがあります。

ID、テキスト、ParentID、DestinationID
1、アプリケーション、(null)、(null)
2、ゲーム、(nu​​ll)、(null)
3、オフィス、1、(ヌル)
4、テキスト編集、1、(null)
5、メディア、(ヌル)、(ヌル)
6、単語、3、1
7、エクセル、3、2
8、クライシス、2、3

必要なのは、メニュー ID を渡すことができるクエリであり、その ID を子として持つアイテムのリストを返します。しかし、宛先への有効なパスを持つ子のみを返す必要があります。上記の例では、ユーザーには最初に (アプリケーション、ゲーム) が表示され、アプリケーションを選択すると (オフィス) が表示されます。Text Editing と Media は、その下に有効な宛先がないため、省略してください。

これに関する最も厄介な点は、特定のメニューに事前に決定された深さが存在しないことです。

編集

今日、問題は MS SQL 2008 で発生しましたが、過去 2 週間で、SQLite と SQL CE に対して同様のソリューションが必要でした。理想的なソリューションは、特定の SQL エンジンに縛られるべきではありません。

4

8 に答える 8

7

SQL サーバーのみですが、Common Table Expressionsの仕事のように聞こえます。

于 2009-01-30T14:06:11.963 に答える
3

データベースでストーミングしている階層/ツリーが頻繁に変更されない場合は、修正されたプレオーダー ツリー トラバーサル (MPTT) アルゴリズムを使用することをお勧めします。これには別のテーブル スキーマが必要になりますが、単純な SQL ステートメント (再帰なしなど) でサブツリー全体を要求できます。

データベースへの階層データの保存に関する記事では、この方法について詳しく説明しています。

あなたの例では、次のツリーを取得します。ここで、赤い数字をノードのの値と緑の右の値と呼びます。

代替テキスト

Officeサブツリーを選択する場合は、次のようにします。

SELECT * FROM tree WHERE left BETWEEN 10 AND 15 AND destination IS NOT NULL

DB が BETWEEN ステートメントをサポートしていない場合は、もちろん left > 10 AND left < 15 と書くことができます。

テーブルは次のようになります。

name         | left | right | destination
------------------------------------------ 
root         | 1    | 17    | NULL
Applications | 7    |  16   |  ...
...
于 2009-02-02T17:25:55.633 に答える
1

他の人が指摘しているように、標準のANSI SQLには、必要なことを実行する方法がありません。このようなもののために、私はかつてSQL 2000に、元雇用主が作成した製品のコンポーネントを追跡するシステムを実装しました。各「製品」は、たとえばネジA500のようなアトミックコンポーネントである可能性があります。このコンポーネントは、「複合」コンポーネントで使用できます。一部のA500ネジと6枚のB120木板は、C90「スタイリッシュなツールボックス」に適合しました。その箱に加えて、より多くのネジとモーター「M500」がカーペットの道具に適合する可能性があります。

私は次のようなテーブル「製品」を設計しました。

ID, PartName, Description
1, A500, "Screw A500"
2, B120, "Wood panel B120"
3, C90, "Stylish tool box C90"
4, M500, "Wood cutter M500"

そして、次のような「ProductComponent」テーブル:

Hierarchy, ComponentID, Amount
0301, 1, 24
0302, 2, 6
0401, 1, 3
0402, 3, 1
0403, 4, 1
040201, 1, 24
040202, 2, 6

秘訣は次のとおりです。フィールド階層は、各製品のIDを表す最初の2文字のVARCHARであり、次の各文字ペアはツリー内のノードを識別します。したがって、製品3は他の2つの製品に依存していることがわかります。製品4は他の2つに依存しており、そのうちの1つは他の2つに依存しています。

このモデルには多くの冗長性がありますが、特定の製品に必要なネジの数を簡単に計算したり、木製パネルが必要な部品をすばやく特定したり、製品が最終的に依存するすべてのコンポーネントのリストを取得したりできます(間接的な依存関係を含む)。そして、特定のレベルより下のツリーをスキャンすることは、単純なLIKEクエリです!

16進表現で2文字を使用することにより、製品を最大256の他の製品に直接依存するように制限しました(これは他の製品に依存する可能性があります)。それ以上が必要な場合は、base 36(26文字と10の数字)またはbase-64を使用するように変更できます。

さらに、このテーブルモデルはAccessとmySQLでも非常にうまく機能します。あなたが持つことができないのは、何らかの形で循環依存関係です。

于 2009-01-31T06:12:52.997 に答える
1

これが興味のある (または悩ましい) 問題である場合は、Joe Celko の Trees and Hierarchies in SQL for Smartiesを確認してください。

于 2009-01-30T14:09:27.870 に答える
0

私が最初に行うことは、目的の列を取り除くことです-階層の観点からは意味がありません(実際には、生きている子行を表現した方法で通知するための一種の2番目の主キーのように見えます)

これは与えるだろう

ID, Item, parentID
1, Applications, (null)
2, Games, (null)
3, Office, 1
4, Text Editing, 1
5, Media, (null)
6, Word, 3
7, Excel, 3
8, Crysis, 2

例えば..

ワード > オフィス > アプリケーションと...

エクセル > オフィス > アプリケーション

...おそらく同じメニュー項目にあるはずです(親ID 3)

どのようにメニューを選択しているのかわかりませんが、パラメーターとして (null) が設定された最初のメニュー ボタンがあり、その後の各クリックで動的に次のパラメーターが順番に保持されるという原則に取り組みます (これは一致するようです)。あなたのコメント)

例えば

最上位メニューをクリック:- 値は (null)

アプリケーションをクリックします:- 値は 1 です

Office をクリック:- 値は 3

destinationID がアクティブな子リンクを表示する (削除できるようにする) 以外に何もしていないと仮定すると、コードは次のようになります。

with items (nodeID, PID, list) as
  (select id, ParentID, item
    from menu
    where id = 9
    union all
  select id, ParentID, item
    from menu
    inner join items on nodeID = menu.ParentID
  )
select *
from items 
where (pid = 9)
and nodeID in (select parentid from menu) 

これは MSSQL 2005+ で動作します

他の理由で宛先 ID が必要な場合は、次のようにコードを修正できます (たとえば、ノード ID が親 ID として設定されていない最下位レベルを返す必要がある場合)。

with items (nodeID, PID, list, dest) as
  (select id, ParentID, item, destinationID
    from menu
    where id = 9
    union all
  select id, ParentID, item, destinationID
    from menu
    inner join items on nodeID = menu.ParentID
)
select *
from items 
where (pid = 9)
and (nodeID in (select parentid from menu) 
  or dest is not null)
于 2009-01-30T21:43:58.670 に答える
0

SQL は、任意の深さの階層を歩くのが得意ではありません。

これらのレコードが 1000 未満の場合は、それらすべてをアプリケーションに取り込み、そこでグラフを作成します。

これらのレコードが 1000 を超える場合は、(SubtreeID 外部キーを追加して) 約 1000 の生のサブツリーにグループ化し、各サブツリーをフェッチして、アプリケーションでサブツリーのグラフを作成します。

于 2009-01-30T14:16:15.783 に答える