如何在 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 PATHPIVOT来完成。但是怎么办?

提前致谢

正如您提到的,您需要将 XML + STUFFPIVOT 结合使用:

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;

LiveDemo

输出:

╔═══════╦══════════╦══════════╦══════════╗
║ SName ║ Subject1 ║ Subject2 ║ Subject3 ║
╠═══════╬══════════╬══════════╬══════════╣
║ A,C   ║       77 ║          ║          ║
║ B     ║          ║       70 ║          ║
║ C     ║          ║          ║       78 ║
╚═══════╩══════════╩══════════╩══════════╝