2009-03-23 40 views
7

にリストをリンクされフェッチ:は、私がこのような構造を持つMySQLデータベースのテーブルを持っているMySQLデータベース

table 
    id INT NOT NULL PRIMARY KEY 
    data .. 
    next_id INT NULL 

私はリンクリストの順番でデータをフェッチする必要があります。例えば、このデータを指定された:

id | next_id 
----+--------- 
    1 |  2 
    2 |  4 
    3 |  9 
    4 |  3 
    9 | NULL 

私はそのために、ID = 1、2、4、3、9の行をフェッチする必要があります。データベースクエリでこれを行うにはどうすればよいですか? (私はクライアント側でそれを行うことができます。これがデータベース側でできるかどうか不思議です。つまり、不可能だと言っても問題ありません。

ターミネーションポイントを持つこともできます(たとえば、10フェッチ後に停止する、または行の一部の条件が真となる)が、これは必須ではありません(クライアント側で実行できます)。私は(私が望む)循環参照をチェックする必要はありません。

+0

追加のインデックステーブルを作成できますか? Billが提案しているクエリの説明計画については、実際に興味があります。主キーを常に見ているので、それほど悪くはないかもしれません。私はあなたのクエリの最初のノードのIDを提供すると仮定しています。 (そうでなければ、残酷になるでしょう)。 10回のラウンドトリップがあります(私が知っていることではなく、あなたが尋ねたものではありません)。問合せで作成されたテンポラリ・テーブルは、特に結果が小さく設定されている場合には、それを実行します。 – TheJacobTaylor

答えて

5

データベースの一部のブランド(Oracle、Microsoft SQL Serverなど)では、「再帰クエリ」を実行するための余分なSQL構文がサポートされていますが、MySQLではこのようなソリューションはサポートされていません。

説明している問題は、SQLデータベースのツリー構造を表すことと同じです。あなたはちょうど長い、痩せた木を持っています。

RDBMSからこの種のデータ構造体を格納およびフェッチするためのソリューションがいくつかあります。あなたは、クエリによって返された "深さ" を制限したいことを言及するので、


:以下の質問のいくつかを参照してください。このようにリストを照会しながらこれを達成することができます:

SELECT * FROM mytable t1 
LEFT JOIN mytable t2 ON (t1.next_id = t2.id) 
LEFT JOIN mytable t3 ON (t2.next_id = t3.id) 
LEFT JOIN mytable t4 ON (t3.next_id = t4.id) 
LEFT JOIN mytable t5 ON (t4.next_id = t5.id) 
LEFT JOIN mytable t6 ON (t5.next_id = t6.id) 
LEFT JOIN mytable t7 ON (t6.next_id = t7.id) 
LEFT JOIN mytable t8 ON (t7.next_id = t8.id) 
LEFT JOIN mytable t9 ON (t8.next_id = t9.id) 
LEFT JOIN mytable t10 ON (t9.next_id = t10.id); 

糖蜜のようなもので、結果は1つの行(リンクされたリストごと)に戻ってくるでしょうが、結果は得られます。

+0

最初のリンクは非常に興味深いです。残念ながら、私はデータベースの構造を変更することはできません。何とか私のニーズに合うように修正できますか?もしそうでなければ、誰かが「はい」と答えるかどうかを待つだろう。 – strager

+0

クレイジーSELECTがあります。 =]私はこれを合理的に達成することは不可能だと言うでしょう。あなたの情報をありがとう! – strager

+0

ええ、私はそのようなSELECTをお勧めしません。しかし、あなたはデータベース構造を変更することができないと言いました。他の選択肢はありません。 –

2

これは解決策ではありませんが、回避策はありませんが、線形リスト(Bill Karwinのツリーではなく)では、リストにソート列を使用する方が効率的かもしれません。たとえば、次のように

TABLE `schema`.`my_table` (
    `id` INT NOT NULL PRIMARY KEY, 
    `order` INT, 
    data .., 
    INDEX `ix_order` (`sort_order` ASC) 
); 

その後:

SELECT * FROM `schema`.`my_table` ORDER BY `order`; 

これが遅くインサートの欠点を持っている(あなたが挿入ポイント過去のすべてのソートされた要素を再配置する必要がある)が、注文の列があるので、検索のため高速である必要がありますインデックスされた。

+0

悲しいことに、他のプログラムが構造に依存しているので、データベース構造を変更できませんでした。あなたの入力をありがとう! – strager

+0

皮肉なことに、これはユーザーが[この質問]で始めた解決策です(http://stackoverflow.com/questions/10594408/insert-record-into-table-with-position-without-updating-all-the回答者はOPがこの質問で使用しているリンクリストスタイルに変更する必要があると述べた。データベースに任意のレコードの順序を格納するのは難しい問題です... – octern

3

避けようとしているのはいくつかのクエリ(ノードごとに1つ)があり、列を追加できる場合、ルートノードにリンクする新しい列を持つことができます。こうすることで、すべてのデータを一度にルートIDで取得できますが、依然としてクライアント側でリスト(またはツリー)をソートする必要があります。もちろん

id | next_id | root_id 
----+---------+--------- 
    1 |  2 |  1 
    2 |  4 |  1 
    3 |  9 |  1 
    4 |  3 |  1 
    9 | NULL |  1 

伝統的なリンクリストや木とは対照的に、このことの欠点は、ルートは(Oの大きさの順に記述することなく変更することができないということである:これで

は、あなたが持っているでしょう例です。 n)ここで、nはノードの数です。これは、各ノードのルートIDを更新する必要があるためです。幸いにも、リスト/ツリーを途中で分割しない限り、単一の更新クエリでこれを実行できるはずです。

+0

このソリューションは非常に素晴らしいです。 – appl3r

関連する問題