SSRS:递归父子
SSRS: Recursive Parent Child
我想使用这个简单的 table 在 SSRS 中创建分层报告?
请你帮助我好吗?我按照这里的教程:https://www.mssqltips.com/sqlservertip/1939/working-with-a-parent-child-hierarchy-in-sql-server-reporting-services-ssrs/
但我无法弄清楚 EmployeeKey 和 ParentEmployeeKey 如何应用于我的 table。就我 table 而言,Col2 是员工,Col1 是父级。但是在 SSRS 中,当我按 Col2 分组并且递归父级是 COL1 时,我没有得到想要的结果。
这是我的 table:
╔══════════════╦══════════════╗
║ COL1 ║ COL2 ║
╠══════════════╬══════════════╣
║ TEST01 ║ TEST02 ║
║ TEST01 ║ TEST03 ║
║ TEST01 ║ TEST04 ║
║ TEST02 ║ LAB ║
║ TEST02 ║ STL40 ║
║ TEST03 ║ LABSTL ║
║ TEST03 ║ STLSCH40 ║
║ TEST04 ║ LABSTL ║
║ TEST04 ║ FLG41 ║
║ TEST04 ║ STLSCH40 ║
╚══════════════╩══════════════╝
这是我想要使用 SSRS 获得的结果。喜欢图片的缩进样式..
╔═══════════════╦══╗
║ COL1 ║ ║
╠═══════════════╬══╣
║ TEST01 ║ ║
║ -TEST02 ║ ║
║ ----LAB ║ ║
║ ----STL40 ║ ║
║ -TEST03 ║ ║
║ ----LABSTL ║ ║
║ ----STLSCH40 ║ ║
║ -TEST04 ║ ║
║ ----LABSTL ║ ║
║ ----FLG41 ║ ║
║ ----STLSCH40 ║ ║
╚═══════════════╩══╝
我不知道如何获得上面的缩进样式结果。我需要使用 HierarchyID 和 IsDescendantOf 还是递归 CTE。
这是我做的 Recursive CTE 和它下的结果。
Declare @Col1 varchar(30)='TEST01';
Declare @BomLevel Integer=0;
WITH tBOM
AS
(
select a.Col1 , a.Col2, @BomLevel "BOMLevel" from Component A
WHERE Col1= @Col1
UNION ALL
Select c.Col1, c.Col2, BomLevel+1 From Component C
INNER JOIN tBOM on tBOM.Col2=c.Col1
)
select Col1,Col2 ,BOMLevel from tbom
Col1 Col2 BOMLevel
TEST01 TEST02 0
TEST01 TEST03 0
TEST01 TEST04 0
TEST02 STL40 1
TEST02 LAB 1
TEST03 STLSCH40 1
TEST03 LABSTL 1
TEST04 STLSCH40 1
TEST04 FLG41 1
TEST04 LABSTL 1
这似乎是一种时髦的方法,但我真的想不出以您期望的格式输出结果的好方法:
CREATE TABLE #table (Col1 NVARCHAR(100), Col2 NVARCHAR(100))
INSERT #table VALUES ('TEST01', 'TEST02')
, ('TEST01', 'TEST03')
, ('TEST01', 'TEST04')
, ('TEST02', 'LAB')
, ('TEST02', 'STL40')
, ('TEST03', 'LABSTL')
, ('TEST03', 'STLSCH40')
, ('TEST04', 'LABSTL')
, ('TEST04', 'FLG41')
, ('TEST04', 'STLSCH40');
WITH CTE1 AS (
SELECT C1.Col1 C1
, C2.Col2 C2
, C3.Col2 C3
, ROW_NUMBER() OVER (ORDER BY C1.Col1, C2.Col2, C3.Col2) RN
FROM (SELECT Col1 FROM #table WHERE Col1 NOT IN (SELECT Col2 FROM #table)) C1
LEFT JOIN #table C2 ON C2.Col1 = C1.Col1
LEFT JOIN #table C3 ON C3.Col1 = C2.Col2
GROUP BY C1.Col1, C2.Col2, C3.Col2)
, CTE2 AS (
SELECT CASE WHEN RN = 1 THEN C1 ELSE NULL END C1
, CASE WHEN RN = 1 THEN CAST('-' + C2 AS NVARCHAR(100))
WHEN (SELECT C2 FROM CTE1 WHERE RN = C.RN-1) = C2 THEN NULL
ELSE CAST('-' + C2 AS NVARCHAR(100)) END C2
, CASE WHEN RN = 1 THEN CAST('----' + C3 AS NVARCHAR(100))
WHEN (SELECT C3 FROM CTE1 WHERE RN = C.RN-1) = C3 THEN NULL
ELSE CAST('----' + C3 AS NVARCHAR(100)) END C3
FROM CTE1 C)
SELECT Col1
FROM CTE2
UNPIVOT (Col1 FOR Col IN (C1, C2, C3)) a
DROP TABLE #table
这输出:
+--------------+
| Col1 |
+--------------+
| TEST01 |
| -TEST02 |
| ----LAB |
| ----STL40 |
| -TEST03 |
| ----LABSTL |
| ----STLSCH40 |
| -TEST04 |
| ----FLG41 |
| ----LABSTL |
| ----STLSCH40 |
+--------------+
...但它假设任何父级的最大深度为 2(根据示例)。如果您比这更深并且您不确定它有多深,那么您需要使用动态 SQL 来产生类似的结果。值得注意的是,如果您想了解如何生成 HTML 列表作为 parent/child table 的输出,我已经在下面的 link 中回答了与此类似的问题:
这应该适用于任何深度(假设您没有为 SORT_PATH 传递 VARCHAR(50))。 'Trick' 当您在层次结构中向下移动时,您构建了一个可以排序的字符串 (SORT_PATH)。最后,我们可以使用 REPLICATE()
和我们的 BOMLevel 来缩进一些东西(在本例中是连字符)。
SET NOCOUNT ON;
DECLARE @Component AS TABLE (
COL1 VARCHAR(50) ,
COL2 VARCHAR(50)
);
INSERT INTO @Component
( COL1, COL2 )
VALUES ( NULL, 'TEST01' ), -- ADDED
( 'TEST01', 'TEST02' ),
( 'TEST01', 'TEST03' ),
( 'TEST01', 'TEST04' ),
( 'TEST02', 'LAB' ),
( 'TEST02', 'STL40' ),
( 'TEST03', 'LABSTL' ),
( 'TEST03', 'STLSCH40' ),
( 'TEST04', 'LABSTL' ),
( 'TEST04', 'FLG41' ),
( 'TEST04', 'STLSCH40' )
;
WITH tBOM
AS ( SELECT A.COL1 , -- PARENT
A.COL2 , -- CURRENT
0 AS "BOMLevel",
CAST(A.COL2 AS VARCHAR(50)) AS SORT_PATH
FROM @Component A
WHERE A.COL1 IS NULL
UNION ALL
SELECT C.COL1 ,
C.COL2 ,
BOMLevel + 1,
CAST(SORT_PATH + '.' + C.COL2 AS VARCHAR(50)) AS SORT_PATH
FROM @Component C
INNER JOIN tBOM ON tBOM.COL2 = C.COL1
)
SELECT COL1 ,
COL2 ,
BOMLevel,
SORT_PATH,
REPLICATE('-', tBOM.BOMLevel) + COL2 AS DISPLAY_PATH
FROM tBOM
ORDER BY SORT_PATH
我想使用这个简单的 table 在 SSRS 中创建分层报告? 请你帮助我好吗?我按照这里的教程:https://www.mssqltips.com/sqlservertip/1939/working-with-a-parent-child-hierarchy-in-sql-server-reporting-services-ssrs/
但我无法弄清楚 EmployeeKey 和 ParentEmployeeKey 如何应用于我的 table。就我 table 而言,Col2 是员工,Col1 是父级。但是在 SSRS 中,当我按 Col2 分组并且递归父级是 COL1 时,我没有得到想要的结果。
这是我的 table:
╔══════════════╦══════════════╗
║ COL1 ║ COL2 ║
╠══════════════╬══════════════╣
║ TEST01 ║ TEST02 ║
║ TEST01 ║ TEST03 ║
║ TEST01 ║ TEST04 ║
║ TEST02 ║ LAB ║
║ TEST02 ║ STL40 ║
║ TEST03 ║ LABSTL ║
║ TEST03 ║ STLSCH40 ║
║ TEST04 ║ LABSTL ║
║ TEST04 ║ FLG41 ║
║ TEST04 ║ STLSCH40 ║
╚══════════════╩══════════════╝
这是我想要使用 SSRS 获得的结果。喜欢图片的缩进样式..
╔═══════════════╦══╗
║ COL1 ║ ║
╠═══════════════╬══╣
║ TEST01 ║ ║
║ -TEST02 ║ ║
║ ----LAB ║ ║
║ ----STL40 ║ ║
║ -TEST03 ║ ║
║ ----LABSTL ║ ║
║ ----STLSCH40 ║ ║
║ -TEST04 ║ ║
║ ----LABSTL ║ ║
║ ----FLG41 ║ ║
║ ----STLSCH40 ║ ║
╚═══════════════╩══╝
我不知道如何获得上面的缩进样式结果。我需要使用 HierarchyID 和 IsDescendantOf 还是递归 CTE。 这是我做的 Recursive CTE 和它下的结果。
Declare @Col1 varchar(30)='TEST01';
Declare @BomLevel Integer=0;
WITH tBOM
AS
(
select a.Col1 , a.Col2, @BomLevel "BOMLevel" from Component A
WHERE Col1= @Col1
UNION ALL
Select c.Col1, c.Col2, BomLevel+1 From Component C
INNER JOIN tBOM on tBOM.Col2=c.Col1
)
select Col1,Col2 ,BOMLevel from tbom
Col1 Col2 BOMLevel
TEST01 TEST02 0
TEST01 TEST03 0
TEST01 TEST04 0
TEST02 STL40 1
TEST02 LAB 1
TEST03 STLSCH40 1
TEST03 LABSTL 1
TEST04 STLSCH40 1
TEST04 FLG41 1
TEST04 LABSTL 1
这似乎是一种时髦的方法,但我真的想不出以您期望的格式输出结果的好方法:
CREATE TABLE #table (Col1 NVARCHAR(100), Col2 NVARCHAR(100))
INSERT #table VALUES ('TEST01', 'TEST02')
, ('TEST01', 'TEST03')
, ('TEST01', 'TEST04')
, ('TEST02', 'LAB')
, ('TEST02', 'STL40')
, ('TEST03', 'LABSTL')
, ('TEST03', 'STLSCH40')
, ('TEST04', 'LABSTL')
, ('TEST04', 'FLG41')
, ('TEST04', 'STLSCH40');
WITH CTE1 AS (
SELECT C1.Col1 C1
, C2.Col2 C2
, C3.Col2 C3
, ROW_NUMBER() OVER (ORDER BY C1.Col1, C2.Col2, C3.Col2) RN
FROM (SELECT Col1 FROM #table WHERE Col1 NOT IN (SELECT Col2 FROM #table)) C1
LEFT JOIN #table C2 ON C2.Col1 = C1.Col1
LEFT JOIN #table C3 ON C3.Col1 = C2.Col2
GROUP BY C1.Col1, C2.Col2, C3.Col2)
, CTE2 AS (
SELECT CASE WHEN RN = 1 THEN C1 ELSE NULL END C1
, CASE WHEN RN = 1 THEN CAST('-' + C2 AS NVARCHAR(100))
WHEN (SELECT C2 FROM CTE1 WHERE RN = C.RN-1) = C2 THEN NULL
ELSE CAST('-' + C2 AS NVARCHAR(100)) END C2
, CASE WHEN RN = 1 THEN CAST('----' + C3 AS NVARCHAR(100))
WHEN (SELECT C3 FROM CTE1 WHERE RN = C.RN-1) = C3 THEN NULL
ELSE CAST('----' + C3 AS NVARCHAR(100)) END C3
FROM CTE1 C)
SELECT Col1
FROM CTE2
UNPIVOT (Col1 FOR Col IN (C1, C2, C3)) a
DROP TABLE #table
这输出:
+--------------+
| Col1 |
+--------------+
| TEST01 |
| -TEST02 |
| ----LAB |
| ----STL40 |
| -TEST03 |
| ----LABSTL |
| ----STLSCH40 |
| -TEST04 |
| ----FLG41 |
| ----LABSTL |
| ----STLSCH40 |
+--------------+
...但它假设任何父级的最大深度为 2(根据示例)。如果您比这更深并且您不确定它有多深,那么您需要使用动态 SQL 来产生类似的结果。值得注意的是,如果您想了解如何生成 HTML 列表作为 parent/child table 的输出,我已经在下面的 link 中回答了与此类似的问题:
这应该适用于任何深度(假设您没有为 SORT_PATH 传递 VARCHAR(50))。 'Trick' 当您在层次结构中向下移动时,您构建了一个可以排序的字符串 (SORT_PATH)。最后,我们可以使用 REPLICATE()
和我们的 BOMLevel 来缩进一些东西(在本例中是连字符)。
SET NOCOUNT ON;
DECLARE @Component AS TABLE (
COL1 VARCHAR(50) ,
COL2 VARCHAR(50)
);
INSERT INTO @Component
( COL1, COL2 )
VALUES ( NULL, 'TEST01' ), -- ADDED
( 'TEST01', 'TEST02' ),
( 'TEST01', 'TEST03' ),
( 'TEST01', 'TEST04' ),
( 'TEST02', 'LAB' ),
( 'TEST02', 'STL40' ),
( 'TEST03', 'LABSTL' ),
( 'TEST03', 'STLSCH40' ),
( 'TEST04', 'LABSTL' ),
( 'TEST04', 'FLG41' ),
( 'TEST04', 'STLSCH40' )
;
WITH tBOM
AS ( SELECT A.COL1 , -- PARENT
A.COL2 , -- CURRENT
0 AS "BOMLevel",
CAST(A.COL2 AS VARCHAR(50)) AS SORT_PATH
FROM @Component A
WHERE A.COL1 IS NULL
UNION ALL
SELECT C.COL1 ,
C.COL2 ,
BOMLevel + 1,
CAST(SORT_PATH + '.' + C.COL2 AS VARCHAR(50)) AS SORT_PATH
FROM @Component C
INNER JOIN tBOM ON tBOM.COL2 = C.COL1
)
SELECT COL1 ,
COL2 ,
BOMLevel,
SORT_PATH,
REPLICATE('-', tBOM.BOMLevel) + COL2 AS DISPLAY_PATH
FROM tBOM
ORDER BY SORT_PATH