我有一个名为[DocType]
的表,列出了各种文档类型以及层级父子关联。我想正确PIVOT
从四列到N个列的数据组。亲子关联的数量不是静态的,我需要考虑分类级别可以达到N个数的情况。
以下是一组数据样本。 Id
是固定密钥。 CatFolderLevel
是层次结构级别 - 值1表示父级,2表示子级,3表示子级,依此类推。 CatParentId
与其父Id
有关。
╔═════╤═════════════════════════════╤════════════════╤═════════════╗
║ Id │ CatName │ CatFolderLevel │ CatParentId ║
╠═════╪═════════════════════════════╪════════════════╪═════════════╣
║ 66 │ Grades │ 1 │ 0 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 68 │ Transcript │ 2 │ 66 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 129 │ Reports │ 1 │ 0 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 137 │ Evaluation Summary │ 2 │ 129 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 317 │ Student Services │ 1 │ 0 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 333 │ Programs - Student Services │ 2 │ 317 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 340 │ Nursing Services │ 3 │ 333 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 352 │ Fine Arts │ 1 │ 0 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 357 │ Budget - Fine Arts │ 2 │ 352 ║
╟─────┼─────────────────────────────┼────────────────┼─────────────╢
║ 358 │ Operational Budget │ 3 │ 357 ║
╚═════╧═════════════════════════════╧════════════════╧═════════════╝
所需的输出将如下所示:
╔══════════╤══════════════════╤══════════════════════╤═══════════════════╤══════════╤═════════════════════════════╤══════════════════════╤═══════════════════╤══════════╤════════════════════╤══════════════════════╤═══════════════════╗
║ Level1ID │ Level1CatName │ Level1CatFolderLevel │ Level1CatParentID │ Level2ID │ Level2CatName │ Level2CatFolderLevel │ Level2CatParentID │ Level3ID │ Level3CatName │ Level3CatFolderLevel │ Level3CatParentID ║
╠══════════╪══════════════════╪══════════════════════╪═══════════════════╪══════════╪═════════════════════════════╪══════════════════════╪═══════════════════╪══════════╪════════════════════╪══════════════════════╪═══════════════════╣
║ 317 │ Student Services │ 1 │ 0 │ 333 │ Programs - Student Services │ 2 │ 317 │ 340 │ Nursing Services │ 3 │ 333 ║
╟──────────┼──────────────────┼──────────────────────┼───────────────────┼──────────┼─────────────────────────────┼──────────────────────┼───────────────────┼──────────┼────────────────────┼──────────────────────┼───────────────────╢
║ 352 │ Fine Arts │ 1 │ 0 │ 357 │ Budget - Fine Arts │ 2 │ 352 │ 358 │ Operational Budget │ 3 │ 357 ║
╟──────────┼──────────────────┼──────────────────────┼───────────────────┼──────────┼─────────────────────────────┼──────────────────────┼───────────────────┼──────────┼────────────────────┼──────────────────────┼───────────────────╢
║ 66 │ Grades │ 1 │ 0 │ 68 │ Transcript │ 2 │ 66 │ NULL │ NULL │ NULL │ NULL ║
╟──────────┼──────────────────┼──────────────────────┼───────────────────┼──────────┼─────────────────────────────┼──────────────────────┼───────────────────┼──────────┼────────────────────┼──────────────────────┼───────────────────╢
║ 129 │ Reports │ 1 │ 0 │ 137 │ Evaluation Summary │ 2 │ 129 │ NULL │ NULL │ NULL │ NULL ║
╚══════════╧══════════════════╧══════════════════════╧═══════════════════╧══════════╧═════════════════════════════╧══════════════════════╧═══════════════════╧══════════╧════════════════════╧══════════════════════╧═══════════════════╝
我用来制作上述样本集的方法是使用CTE(见下文),但它是静态的,坦白地说,对我的尝试感到不满,非常简陋和垃圾。
;WITH Level3 AS(SELECT
Id
,CatName
,CatFolderLevel
,CatParentId
FROM
[DocType]
WHERE
CatFolderLevel = 3)
,Level2 AS (SELECT
Id
,CatName
,CatFolderLevel
,CatParentId
FROM
[DocType]
WHERE
CatFolderLevel = 2)
,Level1 AS (SELECT
Id
,CatName
,CatFolderLevel
,CatParentId
FROM
[DocType]
WHERE
CatFolderLevel = 1)
SELECT
Level1.Id AS 'Level1ID'
,Level1.CatName AS 'Level1CatName'
,Level1.CatFolderLevel 'Level1CatFolderLevel'
,Level1.CatParentId 'Level1CatParentID'
,Level2.Id AS 'Level2ID'
,Level2.CatName AS 'Level2CatName'
,Level2.CatFolderLevel AS 'Level2CatFolderLevel'
,Level2.CatParentId AS 'Level2CatParentID'
,Level3.Id AS 'Level3ID'
,Level3.CatName AS 'Level3CatName'
,Level3.CatFolderLevel AS 'Level3CatFolderLevel'
,Level3.CatParentId AS 'Level3CatParentID'
FROM
Level3
JOIN Level2
ON Level3.CatParentId = Level2.Id
JOIN Level1
ON Level2.CatParentId = Level1.Id
UNION ALL
SELECT
Level1.Id AS 'Level1ID'
,Level1.CatName AS 'Level1CatName'
,Level1.CatFolderLevel 'Level1CatFolderLevel'
,Level1.CatParentId 'Level1CatParentID'
,Level2.Id AS 'Level2ID'
,Level2.CatName AS 'Level2CatName'
,Level2.CatFolderLevel AS 'Level2CatFolderLevel'
,Level2.CatParentId AS 'Level2CatParentID'
,NULL AS 'Level3ID'
,NULL AS 'Level3CatName'
,NULL AS 'Level3CatFolderLevel'
,NULL AS 'Level3CatParentID'
FROM
Level2
JOIN Level1
ON Level2.CatParentId = Level1.Id
我已经使用动态T-SQL探索了PIVOT
的各种用法,但它们都聚合了数据,我不确定如何根据需要动态地正确转换数据而不进行聚合。
有人能指出我正确的方向来产生我想要的结果吗?
答案 0 :(得分:1)
这不是真正的PIVOT。这是一组动态的JOINS。
我将构建一个动态SQL查询,其中我连接N个派生表,其中每个派生表都是CatFolderLevel。每个级别在ID / ParentId配对上连接到它上面的级别。当然,使用OUTER连接,这样你仍然可以得到没有孩子的父母。
答案 1 :(得分:1)
问题是你使用的是union而不是left join。您的查询(在CTE部分之后)可以重写为
SELECT
Level1.Id AS 'Level1ID',
Level1.CatName AS 'Level1CatName',
Level1.CatFolderLevel 'Level1CatFolderLevel',
Level1.CatParentId 'Level1CatParentID',
Level2.Id AS 'Level2ID',
Level2.CatName AS 'Level2CatName',
Level2.CatFolderLevel AS 'Level2CatFolderLevel',
Level2.CatParentId AS 'Level2CatParentID',
Level3.Id AS 'Level3ID',
Level3.CatName AS 'Level3CatName',
Level3.CatFolderLevel AS 'Level3CatFolderLevel',
Level3.CatParentId AS 'Level3CatParentID'
FROM Level1
LEFT JOIN Level2 ON Level2.CatParentId = Level1.Id AND Level2.CatFolderLevel = 2
LEFT JOIN Level3 ON Level3.CatParentId = Level2.Id AND Level3.CatFolderLevel = 3
鉴于此,应该很容易看到如何将此动态变为N级:
SELECT
Level1.Id AS 'Level1ID',
Level1.CatName AS 'Level1CatName',
Level1.CatFolderLevel 'Level1CatFolderLevel',
Level1.CatParentId 'Level1CatParentID',
-- repeat as needed
Level{x}.Id AS 'Level{x}ID',
Level{x}.CatName AS 'Level{x}CatName',
Level{x}.CatFolderLevel AS 'Level{x}CatFolderLevel',
Level{x}.CatParentId AS 'Level{x}CatParentID',
FROM Level1
-- repeat as needed
LEFT JOIN Level{x} ON Level{x}.CatParentId = Level{x-1}.Id AND Level{x}.CatFolderLevel = {x}
答案 2 :(得分:0)
您可以按如下方式生成左连接:您需要提供表名,或者可以相应地更改脚本。我计算表以避免循环。
declare @Query nvarchar(max);
declare @yourtablename nvarchar(50) = '#yourfolder ';
SET @query = 'Select '
;with c1 as ( select * from (values (1), (1),(1), (1),(1), (1),(1), (1),(1), (1)) v(n) )--tally table
, c2 as ( select n1.* from c1 n1, c1 n2, c1 n3, c1 n4 )
, cte1 as ( select top(select max(catfolderlevel) m from #yourfolder) RowN = Row_number() over(order by (select null)) from c2 )
select @Query += concat(' l', RowN,'.Id as Level',RowN,'Id, l',RowN,'.CatName as Level', RowN, 'CatName, l', RowN, '.CatFolderLevel as Level', RowN, 'CatFolder, l', RowN, '.CatParentId as Level', RowN,'CatParentId , ') from cte1
SELECT @Query = left(@query,len(@Query)-2)
Select @query += ' from ' + @yourtablename + ' l1 '
;with c1 as ( select * from (values (1), (1),(1), (1),(1), (1),(1), (1),(1), (1)) v(n) )
, c2 as ( select n1.* from c1 n1, c1 n2, c1 n3, c1 n4 )
, cte1 as ( select top(select max(catfolderlevel)-1 m from #yourfolder) RowN = Row_number() over(order by (select null))+1 from c2 )
Select @Query += concat(' left join #yourfolder l',RowN, ' on l', RowN-1,'.id = l', RowN,'.catparentid and l', RowN-1,'.catfolderlevel = ', RowN -1) from cte1
select @Query += ' Where l1.CatFolderLevel = 1'
select @Query --Check your query
exec sp_executesql @Query
输出:
+----------+------------------+-----------------+-------------------+----------+---------------+-----------------+-----------------------------+----------+--------------------+--------------------+-------------------+---+-----+-----+--------------------+------+------+------+------+------+
| Level1Id | Level1CatName | Level1CatFolder | Level1CatParentId | Level2Id | Level2CatName | Level2CatFolder | Level2CatParentId | Level3Id | Level3CatName | Level3CatFolder | Level3CatParentId | | | | | | | | | |
+----------+------------------+-----------------+-------------------+----------+---------------+-----------------+-----------------------------+----------+--------------------+--------------------+-------------------+---+-----+-----+--------------------+------+------+------+------+------+
| 66 | Grades | | | | | | 1 | 0 | 68 | Transcript | | | | | 2 | 66 | NULL | NULL | NULL | NULL |
| 129 | Reports | | | | | | 1 | 0 | 137 | Evaluation Summary | | | 2 | 129 | NULL | NULL | NULL | NULL | | |
| 317 | Student Services | | | 1 | 0 | 333 | Programs - Student Services | 2 | 317 | 340 | Nursing Services | | | 3 | 333 | | | | | |
| 352 | Fine Arts | | | | | 1 | 0 | 357 | Budget - Fine Arts | | | 2 | 352 | 358 | Operational Budget | | | 3 | 357 | |
+----------+------------------+-----------------+-------------------+----------+---------------+-----------------+-----------------------------+----------+--------------------+--------------------+-------------------+---+-----+-----+--------------------+------+------+------+------+------+
为您的参考生成查询:
Select l1.Id as Level1Id, l1.CatName as Level1CatName, l1.CatFolderLevel as Level1CatFolder, l1.CatParentId as Level1CatParentId , l2.Id as Level2Id, l2.CatName as Level2CatName, l2.CatFolderLevel as Level2CatFolder, l2.CatParentId as Level2CatParentId , l3.Id as Level3Id, l3.CatName as Level3CatName, l3.CatFolderLevel as Level3CatFolder, l3.CatParentId as Level3CatParentId from #yourfolder l1 left join #yourfolder l2 on l1.id = l2.catparentid and l1.catfolderlevel = 1 left join #yourfolder l3 on l2.id = l3.catparentid and l2.catfolderlevel = 2 Where l1.CatFolderLevel = 1