如何在 SQL 服务器中与 FOR XML PATH 结合使用?
How to do pivoting in conjunction with FOR XML PATH in SQL Server?
我有一个输入
DECLARE @T TABLE(SName VARCHAR(20), Subject VARCHAR(20), Marks INT, ExamDate DATE)
INSERT INTO @T
SELECT 'A', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'A', 'Subject2', 97, '2011-01-01' UNION ALL
SELECT 'B', 'Subject1', 80 ,'2012-04-01' UNION ALL
SELECT 'B', 'Subject2', 70, '2012-03-01' UNION ALL
SELECT 'C', 'Subject1', 44, '2011-01-01' UNION ALL
SELECT 'C', 'Subject2', 90, '2011-01-01' UNION ALL
SELECT 'D', 'Subject1', 79 ,'2012-04-01' UNION ALL
SELECT 'D', 'Subject2', 66, '2012-03-01'
SELECT X.*
FROM ( SELECT
t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = 3
输出:
SName Subject Marks ExamDate Rn
A Subject1 77 2011-01-01 3
B Subject2 70 2012-03-01 3
我正在寻找
的输出
SName Subject1 Subject2
----- -------- --------
A 77
B 70
这意味着,由于我们正在寻找学生的第三高分,因此获得第三高分的学生应该进入最终的期望列表。
如果学生 A 和 C(比方说)在科目 1 上打成平手,而学生 C 在科目 3(比方说)中获得第三高分,那么输出将为
SName Subject1 Subject2 Subject3
----- -------- -------- ---------
A,C 77
B 70
C 78
第二个的DDL如下
DECLARE @T TABLE(SName VARCHAR(20), Subject VARCHAR(20), Marks INT, ExamDate DATE)
INSERT INTO @T
SELECT 'A', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'A', 'Subject2', 97, '2011-01-01' UNION ALL
SELECT 'A', 'Subject3', 99, '2011-01-01' UNION ALL
SELECT 'B', 'Subject1', 80 ,'2012-04-01' UNION ALL
SELECT 'B', 'Subject2', 70, '2012-03-01' UNION ALL
SELECT 'B', 'Subject3', 88, '2012-03-01' UNION ALL
SELECT 'C', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'C', 'Subject2', 90, '2011-01-01' UNION ALL
SELECT 'C', 'Subject3', 78, '2011-01-01' UNION ALL
SELECT 'D', 'Subject1', 79 ,'2012-04-01' UNION ALL
SELECT 'D', 'Subject2', 66, '2012-03-01' UNION ALL
SELECT 'D', 'Subject3', 77, '2012-03-01'
SELECT X.*
FROM ( SELECT
t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = 3
我认为应该使用FOR XML PATH
和PIVOT
来完成。但是怎么办?
提前致谢
正如您提到的,您需要将 XML + STUFF
与 PIVOT
结合使用:
DECLARE @rn INT = 3;
;WITH cte AS
(
SELECT X.*
FROM ( SELECT t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = @rn
), cte2 AS
(
SELECT DISTINCT Subject, Marks,
[SName] = STUFF((SELECT ',' + SName
FROM cte c2
WHERE c1.Subject = c2.Subject
ORDER BY SName
FOR XML PATH('')),1,1,'')
FROM cte c1
)
SELECT SName, [Subject1],[Subject2], [Subject3]
FROM cte2
PIVOT
(
MAX(Marks)
FOR Subject IN ([Subject1],[Subject2], [Subject3])
) AS piv;
输出:
╔═══════╦══════════╦══════════╦══════════╗
║ SName ║ Subject1 ║ Subject2 ║ Subject3 ║
╠═══════╬══════════╬══════════╬══════════╣
║ A,C ║ 77 ║ ║ ║
║ B ║ ║ 70 ║ ║
║ C ║ ║ ║ 78 ║
╚═══════╩══════════╩══════════╩══════════╝
我有一个输入
DECLARE @T TABLE(SName VARCHAR(20), Subject VARCHAR(20), Marks INT, ExamDate DATE)
INSERT INTO @T
SELECT 'A', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'A', 'Subject2', 97, '2011-01-01' UNION ALL
SELECT 'B', 'Subject1', 80 ,'2012-04-01' UNION ALL
SELECT 'B', 'Subject2', 70, '2012-03-01' UNION ALL
SELECT 'C', 'Subject1', 44, '2011-01-01' UNION ALL
SELECT 'C', 'Subject2', 90, '2011-01-01' UNION ALL
SELECT 'D', 'Subject1', 79 ,'2012-04-01' UNION ALL
SELECT 'D', 'Subject2', 66, '2012-03-01'
SELECT X.*
FROM ( SELECT
t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = 3
输出:
SName Subject Marks ExamDate Rn
A Subject1 77 2011-01-01 3
B Subject2 70 2012-03-01 3
我正在寻找
的输出SName Subject1 Subject2
----- -------- --------
A 77
B 70
这意味着,由于我们正在寻找学生的第三高分,因此获得第三高分的学生应该进入最终的期望列表。
如果学生 A 和 C(比方说)在科目 1 上打成平手,而学生 C 在科目 3(比方说)中获得第三高分,那么输出将为
SName Subject1 Subject2 Subject3
----- -------- -------- ---------
A,C 77
B 70
C 78
第二个的DDL如下
DECLARE @T TABLE(SName VARCHAR(20), Subject VARCHAR(20), Marks INT, ExamDate DATE)
INSERT INTO @T
SELECT 'A', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'A', 'Subject2', 97, '2011-01-01' UNION ALL
SELECT 'A', 'Subject3', 99, '2011-01-01' UNION ALL
SELECT 'B', 'Subject1', 80 ,'2012-04-01' UNION ALL
SELECT 'B', 'Subject2', 70, '2012-03-01' UNION ALL
SELECT 'B', 'Subject3', 88, '2012-03-01' UNION ALL
SELECT 'C', 'Subject1', 77, '2011-01-01' UNION ALL
SELECT 'C', 'Subject2', 90, '2011-01-01' UNION ALL
SELECT 'C', 'Subject3', 78, '2011-01-01' UNION ALL
SELECT 'D', 'Subject1', 79 ,'2012-04-01' UNION ALL
SELECT 'D', 'Subject2', 66, '2012-03-01' UNION ALL
SELECT 'D', 'Subject3', 77, '2012-03-01'
SELECT X.*
FROM ( SELECT
t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = 3
我认为应该使用FOR XML PATH
和PIVOT
来完成。但是怎么办?
提前致谢
正如您提到的,您需要将 XML + STUFF
与 PIVOT
结合使用:
DECLARE @rn INT = 3;
;WITH cte AS
(
SELECT X.*
FROM ( SELECT t.*
,Rn = DENSE_RANK() OVER(PARTITION BY t.Subject ORDER BY t.Marks DESC)
FROM @T t) X WHERE X.Rn = @rn
), cte2 AS
(
SELECT DISTINCT Subject, Marks,
[SName] = STUFF((SELECT ',' + SName
FROM cte c2
WHERE c1.Subject = c2.Subject
ORDER BY SName
FOR XML PATH('')),1,1,'')
FROM cte c1
)
SELECT SName, [Subject1],[Subject2], [Subject3]
FROM cte2
PIVOT
(
MAX(Marks)
FOR Subject IN ([Subject1],[Subject2], [Subject3])
) AS piv;
输出:
╔═══════╦══════════╦══════════╦══════════╗
║ SName ║ Subject1 ║ Subject2 ║ Subject3 ║
╠═══════╬══════════╬══════════╬══════════╣
║ A,C ║ 77 ║ ║ ║
║ B ║ ║ 70 ║ ║
║ C ║ ║ ║ 78 ║
╚═══════╩══════════╩══════════╩══════════╝