我面向平面视图的问题树视图,我有一些来自树的数据,这些数据存储在左下方的图片中。我说树的顶层是level1,第二层是level2,依此类推。我的预期结果在右下图中表示。
如何在SQL Server中动态地将我的数据转换为我的预期结果?我们必须创建动态列level1,level2,level3等。你有什么主意吗?感谢。
以下是示例数据
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
Id INT NOT NULL,
SomeName VARCHAR(3) NOT NULL,
ParentId INT NULL
);
INSERT #TestData (Id, SomeName, ParentId) VALUES
(1, 'O', NULL),
(2, 'D1', 1),
(3, 'D2', 1),
(4, 'S1', 2),
(5, 'S2', 2),
(6, 'S1', 3),
(7, 'SP1', 3);
SELECT * FROM #TestData td;
答案 0 :(得分:2)
您可以查询如下:
;With Cte as ( --Recursive CTE for traversing tree
Select *, convert(varchar(max),[name]) as NameLevel, 1 as Levl from #TreeData where ParentId is Null
Union all
Select t.Id, t.[Name], t.[ParentId], concat(c.NameLevel,',',t.[name]) as NameLevel, c.Levl + 1 as Levl from Cte c
inner join #TreeData t on c.Id = t.ParentId
)
Select * from (
select c.Id, c.Levl, a.[value]
,RowN = row_number() over(partition by Id order by Levl) from cte c
cross apply string_split(c.NameLevel,',') a
) sq
pivot(max([value]) for RowN in([1],[2],[3])) p --Pivot for getting all data
输出如下:
+---+------+------+----+
| 1 | 2 | 3 | Id |
+---+------+------+----+
| O | NULL | NULL | 1 |
| O | D1 | NULL | 2 |
| O | D2 | NULL | 3 |
| O | D1 | S1 | 4 |
| O | D1 | S2 | 5 |
| O | D2 | S1 | 6 |
| O | D2 | SP1 | 7 |
+---+------+------+----+
在我使用的输入表和数据下面:
Create Table #TreeData(Id int, [name] varchar(10), ParentId int)
Insert into #TreeData(id, [name], ParentId) values
(1,'O', null)
,(2,'D1', 1)
,(3,'D2', 1)
,(4,'S1', 2)
,(5,'S2', 2)
,(6,'S1', 3)
,(7,'SP1', 3)
答案 1 :(得分:1)
以下内容应该为您提供所要求的结果。
注意:此解决方案依赖于使用名为tfn_Tally的iTVF,我会在我的答案下面发布代码。
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
Id INT NOT NULL,
SomeName VARCHAR(3) NOT NULL,
ParentId INT NULL
);
INSERT #TestData (Id, SomeName, ParentId) VALUES
(1, 'O', NULL),
(2, 'D1', 1),
(3, 'D2', 1),
(4, 'S1', 2),
(5, 'S2', 2),
(6, 'S1', 3),
(7, 'SP1', 3);
-- SELECT * FROM #TestData td;
--===========================================
--===========================================
IF OBJECT_ID('tempdb..#RecursionResults', 'U') IS NOT NULL
DROP TABLE #RecursionResults;
WITH
cte_Recursion AS (
SELECT
td.Id,
SomeName = CAST(CAST(td.SomeName AS BINARY(5)) AS VARBINARY(1000)),
--td.ParentId,
NodeLevel = 1
FROM
#TestData td
WHERE
td.ParentId IS NULL
UNION ALL
SELECT
td.Id,
SomeName = CAST(CONCAT(r.SomeName, CAST(td.SomeName AS BINARY(5))) AS VARBINARY(1000)),
NodeLevel = r.NodeLevel + 1
FROM
cte_Recursion r
JOIN #TestData td
ON r.Id = td.ParentId
)
SELECT
Id = ISNULL(r.Id, 0), r.SomeName, r.NodeLevel
INTO #RecursionResults
FROM
cte_Recursion r;
-- adding a clustered index Id eliminates the sort operation on final select.
ALTER TABLE #RecursionResults ADD PRIMARY KEY CLUSTERED (Id);
-----------------------------------------
DECLARE
@PivotCount INT = (SELECT MAX(rr.NodeLevel) FROM #RecursionResults rr),
@PivotCols VARCHAR(1000) = '',
@PivotCAV VARCHAR(8000) = '',
@sql VARCHAR(8000),
@Debug BIT = 0; -- set to 0 to execute, 1 to DeBug.
SELECT TOP (@PivotCount)
@PivotCols = CONCAT(@PivotCols, CHAR(13), CHAR(10), CHAR(9), 'L', t.n, '.Level_', t.n, ','),
@PivotCAV = CONCAT(@PivotCAV, CHAR(13), CHAR(10), CHAR(9), 'CROSS APPLY ( VALUES (CAST(SUBSTRING(rr.SomeName,', (t.n - 1) * 5 + 1, ', ', 5, ') AS VARCHAR(5))) ) L', t.n, ' (Level_', t.n, ')'
)
FROM
dbo.tfn_Tally(@PivotCount, 1) t;
SET @sql = CONCAT('
SELECT ',
STUFF(@PivotCols, 1, 1, ''), '
rr.Id
FROM
#RecursionResults rr',
@PivotCAV, '
ORDER BY
rr.Id;');
IF @Debug = 1
BEGIN
PRINT(@sql);
END;
ELSE
BEGIN
EXEC (@sql);
END;
tfn_Tally的功能代码......
CREATE FUNCTION dbo.tfn_Tally
/* ============================================================================
07/20/2017 JL, Created. Capable of creating a sequense of rows
ranging from -10,000,000,000,000,000 to 10,000,000,000,000,000
============================================================================ */
(
@NumOfRows BIGINT,
@StartWith BIGINT
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH
cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)), -- 10 rows
cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b), -- 100 rows
cte_n3 (n) AS (SELECT 1 FROM cte_n2 a CROSS JOIN cte_n2 b), -- 10,000 rows
cte_n4 (n) AS (SELECT 1 FROM cte_n3 a CROSS JOIN cte_n3 b), -- 100,000,000 rows
cte_Tally (n) AS (
SELECT TOP (@NumOfRows)
(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) + @StartWith
FROM
cte_n4 a CROSS JOIN cte_n4 b -- 10,000,000,000,000,000 rows
)
SELECT
t.n
FROM
cte_Tally t;
GO
HTH, 杰森
答案 2 :(得分:1)
\common\models\leave\table1::updateAllCounters(['id' => 1],$condition);