我有以下情况(严重抽象,请忽略不良设计):
CREATE TABLE dbo.PersonTest (Id INT, name VARCHAR(255))
INSERT INTO dbo.PersonTest
(Id, name )
VALUES (1, 'Pete')
, (1, 'Marie')
, (2, 'Sam')
, (2, 'Daisy')
我正在寻找以下结果:
Id Name1 Name2
1 Marie Pete
2 Daisy Sam
因此,对于每个Id,应该合并行。
获得此结果我使用了以下查询:
WITH PersonRN AS
(
SELECT *
, ROW_NUMBER() OVER(PARTITION BY Id ORDER BY name) RN
FROM dbo.PersonTest
)
SELECT PT1.Id
, PT1.name Name1
, PT2.name Name2
FROM PersonRN AS PT1
LEFT JOIN PersonRN AS PT2 -- Left join in case there's only 1 name
ON PT2.Id = PT1.Id
AND PT2.RN = 2
WHERE PT1.RN = 1
哪种效果很好。
我的问题是:这是最佳方式(在性能和弹性方面最佳)吗?例如,如果其中一个Id具有第三个名称,则我的查询将忽略此第三个名称。我认为最好的处理方式是动态SQL,这很好,但如果没有动态可以做,我宁愿这样做。
答案 0 :(得分:4)
除了动态PIVOT
之外,您可以使用Dynamic Crosstab来执行此操作,我更喜欢这种可读性。
DECLARE @sql1 VARCHAR(1000) = '',
@sql2 VARCHAR(1000) = '',
@sql3 VARCHAR(1000) = ''
DECLARE @max INT
SELECT TOP 1 @max = COUNT(*) FROM PersonTest GROUP BY ID ORDER BY COUNT(*) DESC
SELECT @sql1 =
'SELECT
ID' + CHAR(10)
SELECT @sql2 = @sql2 +
' , MAX(CASE WHEN RN =' + CONVERT(VARCHAR(5), RN)
+ ' THEN name END) AS ' + QUOTENAME('Name' + CONVERT(VARCHAR(5), RN)) + CHAR(10)
FROM(
SELECT TOP(@max)
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RN
FROM sys.columns
)t
ORDER BY RN
SELECT @sql3 =
'FROM(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY name)
FROM PersonTest
)t
GROUP BY ID
ORDER BY ID'
PRINT (@sql1 + @sql2 + @sql3)
EXEC (@sql1 + @sql2 + @sql3)