2017-08-16 10 views
-1

私は、2つの列I1、I2(両方とも別の表への索引)を持つ表を持ち、ツリーを形成しています。TSQLを使用してこのツリーを分割するにはどうすればよいですか?

私のようにリストを引き出したいと思い、そこから
I1 I2 
1 3 
4 6 
2 5 
3 7 
6 9 
8 11 

:今、私は、実行上の一致の数が一致し、同じ数になるまでマッチを探し続けるのコードを使用し

Group Num 
1  1 
1  3 
1  7 
2  4 
2  6 
2  9  
3  8 
3  11 
4  2 
4  5 

前回と同じように。 TSQLを使用してリストを分解する方法はありますか?

+0

「これを行う方法racleはSQLサーバで先に接続する "という質問ですか? –

+0

あなたはどのSQL Serverを使用していますか? –

+2

テーブルから期待される結果の価値をどのように考え出しましたか? –

答えて

2

以前の回答は消去されました。私は今あなたがしようとしていることを完全に理解しています。このソリューションは、あなたの "ツリー"が3レベルまで深い場合に機能します。値(7,20)を挿入した場合は、LEFT JOINとUNION ALLを追加する必要があります。

これはまた、recursive CTEを使用してよりきれいに行うこともできますが、固定数のレベルを扱う場合は、この手法のほうが優れています。

-- your table 
use tempdb 
go 
if object_id('dbo.mytable') is not null drop table dbo.mytable; 
create table dbo.mytable 
(
    I1 int not null, 
    I2 int not null, 
    constraint pk_cl_mytable primary key clustered(I1,I2) 
); 
go 
insert dbo.mytable values (1,3),(4,6),(2,5),(3,7),(6,9),(8,11); 
go 

-- solution 
WITH flatten AS 
(
    SELECT 
    L1 = t1.I1, 
    L2 = t1.I2, 
    L3 = t2.I2 
    FROM dbo.mytable t1 
    LEFT JOIN dbo.mytable t2 ON t1.I2 = t2.I1 
), 
setGroups AS 
(
    SELECT [group] = row_number() over (order by L1), * 
    FROM flatten 
    WHERE L1 NOT IN (SELECT L2 FROM flatten) 
) 
SELECT [group], L1 FROM setGroups 
UNION ALL 
SELECT [group], L2 FROM setGroups WHERE L2 IS NOT NULL 
UNION ALL 
SELECT [group], L3 FROM setGroups WHERE L3 IS NOT NULL 
ORDER BY [group]; -- not required, including for presentation purposes 

結果:

group    L1 
-------------------- ----------- 
1     1 
1     3 
1     7 
2     5 
2     2 
3     4 
3     6 
3     9 
4     11 
4     8 

必要な場合は、各ノードのレベルを呼び出すために、静的なLVL値を含めることで、階層内の各ノードのレベルを含めることができます

WITH flatten AS 
(
    SELECT 
    L1 = t1.I1, 
    L2 = t1.I2, 
    L3 = t2.I2 
    FROM dbo.mytable t1 
    LEFT JOIN dbo.mytable t2 ON t1.I2 = t2.I1 
), 
setGroups AS 
(
    SELECT [group] = row_number() over (order by L1), * 
    FROM flatten 
    WHERE L1 NOT IN (SELECT L2 FROM flatten) 
) 
SELECT [group], L1, lvl = 1 FROM setGroups 
UNION ALL 
SELECT [group], L2, lvl = 2 FROM setGroups WHERE L2 IS NOT NULL 
UNION ALL 
SELECT [group], L3, lvl = 3 FROM setGroups WHERE L3 IS NOT NULL 
ORDER BY [group], lvl; -- not required, including for presentation purposes 

結果:

group L1 lvl 
-------- --- ---- 
1  1 1 
1  3 2 
1  7 3 
2  2 1 
2  5 2 
3  4 1 
3  6 2 
3  9 3 
4  8 1 
4  11 2 
+1

あなたのソリューションを試してみましたが、それは優れています(これは100K +のエントリを持つテーブルのために5秒以下で1時間、私のブルートフォースのソリューションでは動作します)。しかし、私は少なくとも8深く(現在私は7を持っているが、将来的には深く進むことができる)になる解決策が必要です。私はそれを変えずにどのように変えますか? 1つのレベルを追加する方法を私に示すことができれば、追加のレベルを追加することができます。 –

関連する問題