如何在SQL Server中将数据行转换为具有不同列的单行
目前我有来自temp的数据,我从其他表中提取数据。临时表格式如下所示如何在SQL Server中将数据行转换为具有不同列的单行,sql,sql-server,Sql,Sql Server,目前我有来自temp的数据,我从其他表中提取数据。临时表格式如下所示 WorkerID MainDoc SubDoc Value TimeStamp -------- -------- --------- ----- --------- 1224 Doc1 A1 abc 11:40 1234 Doc1 A2 def 11:40 1224 Doc1 B1
WorkerID MainDoc SubDoc Value TimeStamp
-------- -------- --------- ----- ---------
1224 Doc1 A1 abc 11:40
1234 Doc1 A2 def 11:40
1224 Doc1 B1 30 11.40
1234 Doc1 B2 40 11:40
1224 Doc1 C1 50 11:40
1234 Doc1 C1 51 11:50
1224 Doc1 C2 60 11:40
1234 Doc1 C2 61 11:50
1235 Doc1 A1 fgf 11:55
1235 Doc1 A2 vbv 11:55
WorkerID MainDoc Value(1) Value(2) Value(3) Value(4) Value(5) Value(6)
-------- ------- -------- -------- -------- -------- -------- --------
1234 Doc1 abc def 30 40 51 61
1235 Doc1 fgf vbv NULL NULL NULL NULL
当WorkerID相同且格式如下时,我需要将这些行转换为具有最新时间戳值的单行
WorkerID MainDoc SubDoc Value TimeStamp
-------- -------- --------- ----- ---------
1224 Doc1 A1 abc 11:40
1234 Doc1 A2 def 11:40
1224 Doc1 B1 30 11.40
1234 Doc1 B2 40 11:40
1224 Doc1 C1 50 11:40
1234 Doc1 C1 51 11:50
1224 Doc1 C2 60 11:40
1234 Doc1 C2 61 11:50
1235 Doc1 A1 fgf 11:55
1235 Doc1 A2 vbv 11:55
WorkerID MainDoc Value(1) Value(2) Value(3) Value(4) Value(5) Value(6)
-------- ------- -------- -------- -------- -------- -------- --------
1234 Doc1 abc def 30 40 51 61
1235 Doc1 fgf vbv NULL NULL NULL NULL
因此,我如何着手做这件事!谢谢 我很抱歉,因为原始答案有一些逻辑错误,最后我可以有时间来测试它
在这种方法中,我的第一步是使用CTE获取ValueNumber,并获取每个子文档的最后一个值,然后我将这些值作为轴心
WITH subDocs AS (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY SubDoc) vn, SubDoc FROM (SELECT DISTINCT SubDoc FROM #MyTable) A
), cte AS (
SELECT
WorkerID,
MainDoc,
T.SubDoc,
Value,
ROW_NUMBER() OVER (PARTITION BY WorkerID, MainDoc, T.SubDoc ORDER BY TimeStamp DESC) AS rn,
vn
FROM #MyTable T
JOIN subDocs S ON T.subdoc = S.subdoc
)
SELECT WorkerID, MainDoc, [1] as [Value(1)], [2] as [Value(2)], [3] as [Value(3)], [4] as [Value(4)], [5] as [Value(5)], [6] as [Value(6)]
FROM (
SELECT WorkerID, Maindoc, vn, Value FROM cte WHERE rn = 1
) Source
PIVOT (
MAX(Value) FOR vn IN ([1],[2],[3],[4],[5],[6])
) PVT
但最有可能的是,您想要的列数不是固定的,您需要使用动态SQL来获得它
DECLARE @SQL NVARCHAR(MAX);
DECLARE @SubDocCount INT
DECLARE @ColumnNames NVARCHAR(MAX)
DECLARE @PivotValues NVARCHAR(MAX)
SELECT TOP 1 @SubDocCount = COUNT(DISTINCT Subdoc) FROM #MyTable
;WITH cols AS (
SELECT 1 as num
UNION ALL
SELECT num + 1
FROM cols WHERE num < @SubDocCount
)
SELECT
@ColumnNames = STUFF(
(SELECT ',' + QUOTENAME(CAST(num AS VARCHAR)) + ' AS ' + QUOTENAME('Value' + QUOTENAME(CAST(num AS VARCHAR),'('))
FROM cols
FOR XML PATH (''))
, 1, 1, ''),
@PivotValues = STUFF(
(SELECT ',' + QUOTENAME(CAST(num AS VARCHAR))
FROM cols
FOR XML PATH (''))
, 1, 1, '')
SET @SQL = N'
WITH subDocs AS (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY SubDoc) vn, SubDoc FROM (SELECT DISTINCT SubDoc FROM #MyTable) A
), cte AS (
SELECT
WorkerID,
MainDoc,
T.SubDoc,
Value,
ROW_NUMBER() OVER (PARTITION BY WorkerID, MainDoc, T.SubDoc ORDER BY TimeStamp DESC) AS rn,
vn
FROM #MyTable T
JOIN subDocs S ON T.subdoc = S.subdoc
)
SELECT WorkerID, MainDoc, ' + @ColumnNames + '
FROM (
SELECT WorkerID, Maindoc, vn, Value FROM cte WHERE rn = 1
) Source
PIVOT (
MAX(Value) FOR vn IN (' + @PivotValues + ')
) PVT'
EXEC (@SQL)
注意,在您的示例输入中有3个不同的WorkerID,考虑到我假设1224和1234为打字错误的预期结果,google CROSSAPPLY您的时间戳值不一致。前两个值使用冒号,其他值使用点分隔小时和分钟。应该先纠正吗?或者它应该按原样工作?您使用的是哪个SQL版本?对不起,时间戳,我已经对它进行了更改,目前正在使用MS SQL2014@VirVir对不起,我的原始答案,我无法测试它,它充满了错误,理应被否决,现在已修复。。。