web-dev-qa-db-ja.com

接続されているすべての値を単一の列として取得する方法

CTE再帰を使用しようとしています。これが私のシナリオです SQL Fiddle 。これは単純なツリー構造です。

CREATE TABLE [dbo].[AL](
    [IdAL] [int] IDENTITY(1,1) NOT NULL,
    [ID1] [int] NOT NULL,
    [ID2] [int] NOT NULL,
 CONSTRAINT [PK_AL] PRIMARY KEY CLUSTERED 
    (
      [IdAL] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
            ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] ;

INSERT INTO AL (ID1, ID2)
VALUES (1092, 284917), 
       (1092, 248957), 
       (1092, 789475),
       (   1, 789475), 
       (   1,      2), 
       (   3,      2), 
       (   6,      4) ;

簡単に言えば、ユーザーは私にID(1092など)を与えます。テーブル内のすべての行を再帰的に実行し、ユーザーが指定したIDで始まるID(ID1 + ID2)のマージを実行します。

私はこのようなものを取得したいと思います(IDと呼ばれる1つの列だけで):

ID 
 1092、
 284917、
 248957、
 789475、
 1、
 2、
 3

これらのIDを指すノードがないため、ID4と6は結果リストに含まれていないことに注意してください。

4
Yuri Ferrari

これが私の解決策です。以前のコメントで述べたように、これはスタイル的に最も美しいソリューションではありませんが、機能します。

DECLARE @Id int = 1092

DECLARE @i                      INT = 0,
    @IdToProcess    INT = 0

DECLARE @t TABLE    (   Id  INT,
                    Processed   BIT
                )

INSERT INTO @t (Id, Processed)
VALUES (@Id, 0)

WHILE   (1 = 1 OR @i <= 100)
BEGIN
 SET @i = @i +1
SET @IdToProcess = 0

SELECT  @IdToProcess = MIN(Id)
FROM    @t
WHERE   Processed = 0

SET @IdToProcess = ISNULL(@IdToProcess, 0)

IF @IdToProcess <= 0
BEGIN
    BREAK
END

INSERT INTO @t (Id, Processed)
SELECT  AL.Id2, 0
FROM    dbo.AL AL
WHERE   AL.Id1 = @IdToProcess
        AND NOT EXISTS (SELECT 1 FROM @t T WHERE T.Id = AL.Id2)
UNION
SELECT  AL.Id1, 0
FROM    dbo.AL AL
WHERE   AL.Id2 = @IdToProcess
        AND NOT EXISTS (SELECT 1 FROM @t T WHERE T.Id = AL.Id1)

UPDATE  @t
SET     Processed = 1
WHERE   Id = @IdToProcess
END

SELECT * FROM @T
0
Yuri Ferrari