これらの「from」と「to」の関係が双方向であるため (両方向をトラバースする必要があります)、MySQL でそれを行うための簡単なステートメントはありません。単一の列で返される単一の結果セット内のすべてのノード値を取得するには、UNION 操作を回避するのに最も近い方法は次のとおりです。
SELECT CASE
WHEN t.i = 1 THEN t.dnode
WHEN t.i = 2 AND t.dnode = c.fromnode THEN c.tonode
WHEN t.i = 2 AND t.dnode = c.tonode THEN c.fromnode
ELSE NULL
END AS node
FROM ( SELECT d.i
, m.root
, CASE WHEN m.root = n.fromnode THEN n.tonode ELSE n.fromnode END AS dnode
FROM (SELECT 'node1' AS root) m
CROSS
JOIN (SELECT 1 AS i UNION ALL SELECT 2) d
LEFT
JOIN conn n ON m.root IN (n.fromnode,n.tonode)
) t
LEFT
JOIN conn c
ON t.i = 2 AND t.dnode IN (c.fromnode,c.tonode)
GROUP BY node
ORDER BY node
開梱できるかどうかもわかりませんが、やってみます。ルート ノード 'node1' を複数回指定する必要がないように、サブクエリを使用してそれを返します。
(SELECT 'node1' AS root) m
「2 レベルの深さ」に進むため、2 セットのノードが必要です。そのため、取得した行数を 2 倍にするデカルト積を作成し、最初のレベルに 1、2 にラベルを付けます。 2番目のレベル。
CROSS
JOIN (SELECT 1 AS i UNION ALL SELECT 2) d
これで、テーブルに参加する準備が整いましたconn
。ルート ノードと一致する fromnode または tonode 値を持つすべての行が必要です。
LEFT
JOIN conn n ON m.root IN (n.fromnode,n.tonode)
その結果セットを使用して、これらの行のいくつかで fromnode と tonode を「反転」して、基本的に常に一方の側に「ルート」ノードがあるようにします。どちらの側がルートに一致するかをテストする CASE 式を使用してこれを行います。
CASE WHEN m.root = n.fromnode THEN n.tonode ELSE n.fromnode END AS dnode
そのため、その結果セットをエイリアス化されたインライン ビューとしてラップしますt
。そのサブクエリを個別に実行して、期待どおりの結果が返されていることを確認できます。
SELECT d.i
, m.root
, CASE WHEN m.root = n.fromnode THEN n.tonode ELSE n.fromnode END AS dnode
FROM (SELECT 'node1' AS root) m
CROSS
JOIN (SELECT 1 AS i UNION ALL SELECT 2) d
LEFT
JOIN conn n ON m.root IN (n.fromnode,n.tonode)
その「レベル」値を返す必要があります (d.i
前に生成しました。次のステップで、conn テーブルに再び結合するときに必要です。次のレベルをトラバースします。目的の行を結合するだけで済みます。 2 番目のレベルを見てください。
LEFT
JOIN conn c
ON t.i = 2 AND t.dnode IN (c.fromnode,c.tonode)
繰り返しになりますが、どちらの側のノードがオンになっているかは気にしません。この時点では、マッチを実行するだけです。
この時点で、クエリ全体を実行し、t.*, c.*
取得したものをプルして確認することもできますが、その部分はスキップして、「魔法」に直行します。
この時点で、CASE 式を使用して、その混乱から必要なノード値を「選択」できます。
レベル値 (残念ながら とラベル付けされi
ています) が 1 の場合、最初のレベルを見ているので、「ルート」の「反対側」にあった「nodeX」値を取得する必要があります。t
これは、としてエイリアス化された式としてソースから入手できますdnode
。
それ以外の場合は、「第 2」レベルの行を見ていきますi = 2
。(この特定のケースでは、上のテストはi = 2
省略できますが、完全を期すために、このアプローチを拡張して 3 つ (あえぎ!) またはそれ以上 (おっと!) のレベルを取得する場合に備えて、hear が含まれています。
ここでは、どちらの側 (from または to) が最初のレベルに一致したかを知る必要があり、反対側をプルするだけです。片側が一致する場合t.dnode
は、反対側を引っ張ります。
最後に、GROUP BY を使用して重複を折りたたみます。
これらがどのレベルからのものであるかは気にしないので、レベルを返す を省略t.i
します。
まとめ
これはあなたのクエリよりも簡単だとは思いません。そして、パフォーマンスがどのように比較されるかはわかりません。ただし、パフォーマンスを比較する他のステートメントがあると便利です。