如何在不知道 T-SQL 中的固定列的情况下旋转
How to pivot without knowing fixed columns in T-SQL
我有一个名为 balance
的 table,我希望对其进行透视,但是这非常困难,因为列名称将标记为 1、2、3 并且余额将按降序排序每个客户。
这是当前 table 的屏幕截图:
和枢轴table:
我查看了其他视频和 post 但我没有找到符合我当前情况的解决方案,我想达到的目标。因此最终结果将是客户按升序排序,余额按降序排序。因此,对于客户 3,最高余额 500 将放在第 1 列,300 放在第 2 列,250 放在第 3 列。
创建示例数据的脚本:
select Customer, Balance
into #a
from (
values
(1, 250),
(2, 500),
(1, 205),
(2, 600),
(2, 700),
(3, 300),
(3, 500),
(3, 250)
) v (Customer, Balance)
您可以使用ROW_NUMBER()
来标记值的个数,例如:1, 2, 3
.
注意:ORDER BY [Balance] DESC
来获取你想要的生成值
DECLARE
@columns NVARCHAR(MAX) = '',
@sql NVARCHAR(MAX) = '';
SELECT Customer, Balance, Col = ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY [Balance] DESC)
into #b
FROM #a
SELECT @columns += QUOTENAME(Col) + ','
from (SELECT DISTINCT Col FROM #b) A
-- remove the last comma
SET @columns = LEFT(@columns, LEN(@columns) - 1);
SET @sql = 'SELECT * FROM ( SELECT Customer, Balance, Col FROM #b) src PIVOT( MAX([Balance]) FOR Col IN ('+ @columns +')) AS pivot_table;';
-- execute the dynamic SQL
EXECUTE sp_executesql @sql;
输出
已更新
自连接字符串后 is undocumented and unreliable。它并不总是按预期工作。所以你应该用下面的 2 个解决方案来解决
- 使用 STRING_AGG(来自 SQL Server 2017 及以后版本)
SELECT STRING_AGG(QUOTENAME(Col), ', ')
from (SELECT DISTINCT Col FROM #b) A
// Output: [1], [2], [3]
- 使用XML Extensions
DECLARE @columns NVARCHAR(MAX) = ''
SELECT @columns = (
SELECT QUOTENAME(Col) + ', '
FROM (SELECT DISTINCT Col FROM #b) A
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
SELECT @columns
// Output: [1], [2], [3],
感谢@GarethD 的评论。在 db<>fiddle
上查看
你可以这样试试
select *,concat('Price',RANK() OVER (PARTITION BY i.REFERENCE_NO ORDER BY i.TASK_ID
DESC)) AS Rank into #temp from [dbo].[Table_1] i
select REFERENCE_NO,Price1,Price2,Price3 from
(
select REFERENCE_NO,TASK_ID,Rank from #temp
) as cte
PIVOT (SUM(TASK_ID)
FOR rank IN (Price1,Price2,Price3 ))
as PVT
试试这个。
declare @balanceAMTCols varchar(max)='',
@statement nvarchar(4000)=''
select @balanceAMTCols= stuff(
(
select ','+ QUOTENAME(balanceamtcol) from (
select distinct convert(varchar(10),(row_number() over(partition by Customer order by Customer)))
balanceamtcol FROM #a ) as tbl
for xml path('')),1,1,'')
set @statement= 'select Customer,'+@balanceAMTCols+' from (
select Customer,Balance,convert(varchar(10),(row_number() over(partition by Customer order by Customer))) as balanceamtcol FROM #a
) [CustomerTbl]
pivot
(
max(Balance)
for balanceamtcol
in ('+@balanceAMTCols+') ) as pivatetble'
exec sp_executesql @statement
我有一个名为 balance
的 table,我希望对其进行透视,但是这非常困难,因为列名称将标记为 1、2、3 并且余额将按降序排序每个客户。
这是当前 table 的屏幕截图:
和枢轴table:
我查看了其他视频和 post 但我没有找到符合我当前情况的解决方案,我想达到的目标。因此最终结果将是客户按升序排序,余额按降序排序。因此,对于客户 3,最高余额 500 将放在第 1 列,300 放在第 2 列,250 放在第 3 列。
创建示例数据的脚本:
select Customer, Balance
into #a
from (
values
(1, 250),
(2, 500),
(1, 205),
(2, 600),
(2, 700),
(3, 300),
(3, 500),
(3, 250)
) v (Customer, Balance)
您可以使用ROW_NUMBER()
来标记值的个数,例如:1, 2, 3
.
注意:ORDER BY [Balance] DESC
来获取你想要的生成值
DECLARE
@columns NVARCHAR(MAX) = '',
@sql NVARCHAR(MAX) = '';
SELECT Customer, Balance, Col = ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY [Balance] DESC)
into #b
FROM #a
SELECT @columns += QUOTENAME(Col) + ','
from (SELECT DISTINCT Col FROM #b) A
-- remove the last comma
SET @columns = LEFT(@columns, LEN(@columns) - 1);
SET @sql = 'SELECT * FROM ( SELECT Customer, Balance, Col FROM #b) src PIVOT( MAX([Balance]) FOR Col IN ('+ @columns +')) AS pivot_table;';
-- execute the dynamic SQL
EXECUTE sp_executesql @sql;
输出
已更新
自连接字符串后 is undocumented and unreliable。它并不总是按预期工作。所以你应该用下面的 2 个解决方案来解决
- 使用 STRING_AGG(来自 SQL Server 2017 及以后版本)
SELECT STRING_AGG(QUOTENAME(Col), ', ')
from (SELECT DISTINCT Col FROM #b) A
// Output: [1], [2], [3]
- 使用XML Extensions
DECLARE @columns NVARCHAR(MAX) = ''
SELECT @columns = (
SELECT QUOTENAME(Col) + ', '
FROM (SELECT DISTINCT Col FROM #b) A
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
SELECT @columns
// Output: [1], [2], [3],
感谢@GarethD 的评论。在 db<>fiddle
上查看你可以这样试试
select *,concat('Price',RANK() OVER (PARTITION BY i.REFERENCE_NO ORDER BY i.TASK_ID
DESC)) AS Rank into #temp from [dbo].[Table_1] i
select REFERENCE_NO,Price1,Price2,Price3 from
(
select REFERENCE_NO,TASK_ID,Rank from #temp
) as cte
PIVOT (SUM(TASK_ID)
FOR rank IN (Price1,Price2,Price3 ))
as PVT
试试这个。
declare @balanceAMTCols varchar(max)='',
@statement nvarchar(4000)=''
select @balanceAMTCols= stuff(
(
select ','+ QUOTENAME(balanceamtcol) from (
select distinct convert(varchar(10),(row_number() over(partition by Customer order by Customer)))
balanceamtcol FROM #a ) as tbl
for xml path('')),1,1,'')
set @statement= 'select Customer,'+@balanceAMTCols+' from (
select Customer,Balance,convert(varchar(10),(row_number() over(partition by Customer order by Customer))) as balanceamtcol FROM #a
) [CustomerTbl]
pivot
(
max(Balance)
for balanceamtcol
in ('+@balanceAMTCols+') ) as pivatetble'
exec sp_executesql @statement