use*_*739 29 sql t-sql sql-server-2005
除了将光标写入每行并将其填充到列中之外,如果我需要将每行转置为列,还有其他任何替代方法吗?
TimeSeconds TagID Value
1378700244 A1 3.75
1378700245 A1 30
1378700304 A1 1.2
1378700305 A2 56
1378700344 A2 11
1378700345 A3 0.53
1378700364 A1 4
1378700365 A1 14.5
1378700384 A1 144
1378700384 A4 10
Run Code Online (Sandbox Code Playgroud)
列数不固定.
输出:我刚刚将n/a指定为占位符,该交集中没有数据.
TimeSec A1 A2 A3 A4
1378700244 3.75 n/a n/a n/a
1378700245 30 n/a n/a n/a
1378700304 1.2 n/a n/a n/a
1378700305 n/a 56 n/a n/a
1378700344 n/a 11 n/a n/a
1378700345 n/a n/a 0.53 n/a
1378700364 n/a n/a n/a 4
1378700365 14.5 n/a n/a n/a
1378700384 144 n/a n/a 10
Run Code Online (Sandbox Code Playgroud)
希望您能与我分享一些提示.谢谢.
pet*_*erm 40
如果tagID预先知道值,则执行此操作的一种方法是使用条件聚合
SELECT TimeSeconds,
COALESCE(MAX(CASE WHEN TagID = 'A1' THEN Value END), 'n/a') A1,
COALESCE(MAX(CASE WHEN TagID = 'A2' THEN Value END), 'n/a') A2,
COALESCE(MAX(CASE WHEN TagID = 'A3' THEN Value END), 'n/a') A3,
COALESCE(MAX(CASE WHEN TagID = 'A4' THEN Value END), 'n/a') A4
FROM table1
GROUP BY TimeSeconds
Run Code Online (Sandbox Code Playgroud)
或者如果你没有使用NULL值而不是'n/a'
SELECT TimeSeconds,
MAX(CASE WHEN TagID = 'A1' THEN Value END) A1,
MAX(CASE WHEN TagID = 'A2' THEN Value END) A2,
MAX(CASE WHEN TagID = 'A3' THEN Value END) A3,
MAX(CASE WHEN TagID = 'A4' THEN Value END) A4
FROM table1
GROUP BY TimeSeconds
Run Code Online (Sandbox Code Playgroud)
或者 PIVOT
SELECT TimeSeconds, A1, A2, A3, A4
FROM
(
SELECT TimeSeconds, TagID, Value
FROM table1
) s
PIVOT
(
MAX(Value) FOR TagID IN (A1, A2, A3, A4)
) p
Run Code Online (Sandbox Code Playgroud)
输出(带NULLs):
TimeSeconds A1 A2 A3 A4 ----------- ------- ------ ----- ----- 1378700244 3.75 NULL NULL NULL 1378700245 30.00 NULL NULL NULL 1378700304 1.20 NULL NULL NULL 1378700305 NULL 56.00 NULL NULL 1378700344 NULL 11.00 NULL NULL 1378700345 NULL NULL 0.53 NULL 1378700364 4.00 NULL NULL NULL 1378700365 14.50 NULL NULL NULL 1378700384 144.00 NULL NULL 10.00
如果必须TagID动态计算值,请使用动态SQL
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX)
SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(TagID)
FROM Table1
ORDER BY 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET @sql = 'SELECT TimeSeconds, ' + @cols + '
FROM
(
SELECT TimeSeconds, TagID, Value
FROM table1
) s
PIVOT
(
MAX(Value) FOR TagID IN (' + @cols + ')
) p'
EXECUTE(@sql)
Run Code Online (Sandbox Code Playgroud)
sar*_*rme 10
SQL Server有一个可能正在寻找的PIVOT命令.
select * from Tag
pivot (MAX(Value) for TagID in ([A1],[A2],[A3],[A4])) as TagTime;
Run Code Online (Sandbox Code Playgroud)
如果列不是常量,则必须将其与某些动态SQL结合使用.
DECLARE @columns AS VARCHAR(MAX);
DECLARE @sql AS VARCHAR(MAX);
select @columns = substring((Select DISTINCT ',' + QUOTENAME(TagID) FROM Tag FOR XML PATH ('')),2, 1000);
SELECT @sql =
'SELECT *
FROM TAG
PIVOT
(
MAX(Value)
FOR TagID IN( ' + @columns + ' )) as TagTime;';
execute(@sql);
Run Code Online (Sandbox Code Playgroud)
小智 10
在这种情况下可能适合的另一个选择是使用XML
将行转换为列的XML选项基本上是PIVOT的最佳版本,因为它解决了动态列限制.
该脚本的XML版本通过结合使用XML Path,动态T-SQL和一些内置函数(即STUFF,QUOTENAME)来解决此限制.
垂直扩展
与PIVOT和Cursor类似,可以在脚本的XML版本中检索新添加的策略,而无需更改原始脚本.
水平扩展
与PIVOT不同,可以在不更改脚本的情况下显示新添加的文档.
性能细分
就IO而言,脚本的XML版本的统计信息几乎与PIVOT类似 - 唯一的区别是XML有第二次扫描dtTranspose表,但这次是从逻辑读取 - 数据缓存.
您可以在本文中找到有关这些解决方案的更多信息(包括一些实际的T-SQL exmaples):https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/