问题
I have a table called balance
which I wish to pivot, however it is quite difficult since the column names would be labelled 1,2,3 and balances would be sorted by descending order per customer.
This is screenshot of current table:
And the pivot table:
I reviewed other videos and post but I didn't find a solution to match my current situation what I want to achieve. So the final results would be the customer would be sorted by asc and balances would be sorted by desc. So for customer 3 the highest balance of 500 would be placed in column 1, 300 in column 2 and in 250 in column 3.
Script to create sample data:
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)
回答1:
Demo on db<>fiddle
You can use ROW_NUMBER() to mark the number of values, e.g: 1, 2, 3
.
Note that: ORDER BY [Balance] DESC
to get the generated value as you wish.
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;
Output
Updated
Since concatenating strings is undocumented and unreliable. It does not always work as expected. So you should resolve with 2 solutions below
- Use STRING_AGG (From SQL Server 2017 and late)
SELECT STRING_AGG(QUOTENAME(Col), ', ')
from (SELECT DISTINCT Col FROM #b) A
// Output: [1], [2], [3]
- Use 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],
Thanks @GarethD's comment. Check it out on db<>fiddle
回答2:
Try this.
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
回答3:
You can try this way
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
来源:https://stackoverflow.com/questions/60331041/how-to-pivot-without-knowing-fixed-columns-in-t-sql