2017-10-11 18 views
0

在過去兩天中,我一直試圖找到一個儘可能動態的高效解決方案,但我無法做到。你有沒有提示下面的例子?我嘗試了一個遞歸調用,以獲得下面的結果到目前爲止的「級別」或本機連接。使用T-SQL有效地構建DWH從父 - 子表格

我有 「initTable」:

parent | child 
-------+------ 
    A | H 
    A | B 
    A | C 
    B | D 
    B | G 
    C | F 
    D | E 

我想有 「finalTable」:(與動態創建列 「levelX」 的bescase

level1 | level2 | level 3 | level 4 
-------+--------+---------+--------- 
    A | A | A  | H 
    A | A | C  | F 
    A | A | B  | G 
    A | B | D  | E 

嘗試#1:遞歸方式獲得水平

問:是否有可能在遞歸過程中爲每個級別創建一列?

WITH recTable (father, child, lev) AS 
(
    SELECT 
     p1.father, 
     p1.child, 
     0 as lev 
    FROM 
     initTable AS p1 
    WHERE 
     p1.father = 'A' 

    UNION ALL 

    SELECT 
     p1.father, 
     p1.child, 
     lev+1 
    FROM 
     initTable AS p1 
    INNER JOIN 
     recTable as p2 ON p1.father = p2.child 
) 
SELECT * FROM ASD 

嘗試#2:但 「錯誤」 訂單

在這裏,我需要填補列 「向後」 莫名其妙......

SELECT 
    p1.child AS Level 1, 
    p2.child AS Level 2, 
    p3.child AS Level 3, 
    p4.child AS Level 4 
FROM 
    initTable p1 
LEFT JOIN 
    initTable p2 ON p1.child = p2.father 
LEFT JOIN 
    initTable p3 ON p2.child = p3.father 
LEFT JOIN 
    initTable p4 ON p3.child = p4.father 
WHERE 
    p1.father= 'A' 

是否有人知道好的和有效的方法來解決這個問題?我覺得我很接近,但目前爲止我還無法解決這個問題。

+0

我沒有看到你想達到什麼樣的邏輯。例如,在第1行A-A-A-H中,這是什麼意思?對我來說,它看起來就像是A-H,但是你用頂級父母填充它,所以你在所有字段中都有值? –

+0

準確地說,我想在所有字段的「父」值爲dwh報告原因 – Kevinski42

+1

@marc_s:謝謝編輯帖子(現在我知道它是如何做到這一點) – Kevinski42

回答

0

以下是動態的,會爲你的工作,例如,以及任何與增加/減少父/子關係:

-- Get the number of required fields 

SELECT 
    parent 
    , child 
    , 1 [level] 
INTO #checking 
FROM initTable 
WHERE parent NOT IN (SELECT child FROM initTable) 
; 

WHILE EXISTS (SELECT * FROM #checking c JOIN initTable t ON c.child = t.parent) 
BEGIN 

    INSERT INTO #checking 

    SELECT 
     t.parent 
     , t.child 
     , (SELECT MAX([level]) + 1 FROM #checking) 
    FROM 
     #checking c 
     JOIN initTable t ON c.child = t.parent 
    ; 

    DELETE 
    FROM #checking 
    WHERE [level] <> (SELECT MAX([level]) FROM #checking) 
    ; 

END 
; 

DECLARE @requiredLevels int = (SELECT TOP 1 [level] + 1 FROM #checking) 
; 

DROP TABLE #checking 
; 

-- Build a dynamic statement for the SELECT fields 

DECLARE 
    @fieldSQL varchar(1000) = '' 
    , @fieldsN int = @requiredLevels 
; 

WHILE @fieldsN > 0 
BEGIN 

    IF @fieldsN > 2 
     BEGIN 

      DECLARE 
       @coalesceFields varchar(1000) = '' 
       , @coalesceN int = @fieldsN 

      WHILE @coalesceN > 1 
      BEGIN 

       IF @coalesceFields = '' 
        SET @coalesceFields = 'L' + CAST(@coalesceN AS varchar) + '.parent' 
       ELSE 
        SET @coalesceFields = @coalesceFields + ', L' + CAST(@coalesceN AS varchar) + '.parent' 
       ; 

       SET @coalesceN = @coalesceN - 1 

      END 

      SET @fieldSQL = @fieldSQL + ', COALESCE(' + @coalesceFields + ') [level ' + CAST(@requiredLevels - @fieldsN + 1 AS varchar) + ']' 

     END 
    ELSE 
     SET @fieldSQL = @fieldSQL + ', L' + CAST(@fieldsN AS varchar) + '.' + CASE WHEN @fieldsN = 1 THEN 'child' ELSE 'parent' END + ' [level ' + CAST(@requiredLevels - @fieldsN + 1 AS varchar) + ']' 
    ; 

    SET @fieldsN = @fieldsN - 1 

END 

SET @fieldSQL = SUBSTRING(@fieldSQL, 3, LEN(@fieldSQL) - 2) 

-- Build a dynamic statement for the LEFT JOINs 

DECLARE 
    @joinSQL varchar(1000) = '' 
    , @joinsN int = 2 

WHILE @joinsN <= @requiredLevels 
BEGIN 

    SET @joinSQL = @joinSQL + ' LEFT JOIN initTable L' + CAST(@joinsN AS varchar) + ' ON L' + CAST(@joinsN - 1 AS varchar) + '.' + CASE WHEN @joinsN = 2 THEN 'child' ELSE 'parent' END + ' = L' + CAST(@joinsN AS varchar) + '.child' 

    SET @joinsN = @joinsN + 1 

END 

-- Build the final SQL statement and execute 

DECLARE @SQL varchar(8000) = 
    ' 
     SELECT ' + @fieldSQL + ' 
     FROM 
      (
       SELECT child 
       FROM initTable 
       WHERE child NOT IN (SELECT parent FROM initTable) 
      ) L1' + @joinSQL 

EXEC (@SQL) 
+0

嗨克里斯!感謝您的快速回復和解決方案 - 它幾乎完美並且幫助了我很多(儘管我花了一些時間來理解它)。它解決了向後動態的建築完美,我正在努力採用它來填充「A」值到1級(目前在我的情況下是空的,即我上面的示例中的第1行的結果是:_ | _ | A | H而不是A | A | A | H)。 – Kevinski42

+0

你有沒有改變腳本?我得到了填滿該行的「A」值,「COALESCE」陳述正在照顧這一點。可能值得添加一個'PRINT @ SQL'並將其作爲靜態查詢進行調試,以查看發生了什麼問題。 –

+0

是的,現在它也適用於我 - 我沒有注意到有一個關係_ |在initTable中的一個「_」裏填滿了。現在它工作了!非常感謝你的幫助,真是太棒了! – Kevinski42