过去两天,我一直试图找到一个尽可能最有活力的有效解决方案,但我无法做到。您是否有以下示例的提示?我尝试了一个递归调用来获得"等级"或者到目前为止的本机连接以及下面的结果。
我有" initTable":
parent | child
-------+------
A | H
A | B
A | C
B | D
B | G
C | F
D | E
我想要" finalTable" :(在bescase中动态创建列" levelX"
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 :但是"错误"为了
在这里,我需要填写列#34;向后"不知何故...
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 :(得分: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)