PIVOT query on Distinct records
If you add a ROW_NUMBER() into the mix, your pivot will be able to retain the association between activities and percentages.
;with cte as
(
select *, ROW_NUMBER() over (partition by name order by percentage desc) ROWNUM
from A
),
cte2 as
(
SELECT Id,Code,ROWNUM,James,James_,Sam,Sam_,Lisa,Lisa_
FROM cte
PIVOT(MAX(activity)
FOR name IN (James,Sam,Lisa)) AS PVTTable PIVOT
(
MAX(percentage)
FOR name1 IN (James_,Sam_,Lisa_)) AS PVTTable1
)
select Id, Code, MAX(James) James, MAX(James_) James_, MAX(Sam) Sam, MAX(Sam_) Sam_, MAX(Lisa) Lisa, MAX(Lisa_) Lisa_
from cte2
group by Id, Code, ROWNUM
Returns:
Id Code James James_ Sam Sam_ Lisa Lisa_
1 Prashant Running 43.43 Cooking 1 73 Walking 90.34
1 Prashant Stealing 0.00 Cooking 3.43 NULL NULL
1 Prashant Lacking 0.00 NULL NULL NULL NULL
The idea is, in thefirst common table expression, you transform the A table to this:
Id Code percentage name name1 activity ROWNUM
1 Prashant 43.43 James James_ Running 1
1 Prashant 0.00 James James_ Stealing 2
1 Prashant 0.00 James James_ Lacking 3
1 Prashant 90.34 Lisa Lisa_ Walking 1
1 Prashant 73 Sam Sam_ Cooking 1 1
1 Prashant 3.43 Sam Sam_ Cooking 2
And throughout the remaining query, the ROWNUM column just acts to bind the percentage value to the activity.
Making it dynamic is easy once you have a working query. Just replace all the dynamic parts (in this case, comma-delimited lists of names, right?) with variables. Something like this:
declare @sql nvarchar(max)
declare @name_concat nvarchar(max)
declare @name1_concat nvarchar(max)
declare @select_aggs nvarchar(max)
select @name_concat = STUFF((select distinct ',' + quotename(name) from A order by 1 for xml path('')), 1, 1, '')
select @name1_concat = STUFF((select distinct ',' + quotename(name1) from A order by 1 for xml path('')), 1, 1, '')
;with cte_all_names as (
select name from A
union all
select name1 from A
)
select @select_aggs = STUFF((select distinct ',MAX(' + quotename(name) + ') ' + quotename(name) from cte_all_names order by 1 for xml path('')), 1, 1, '')
select @sql = '
;with cte as
(
select *, ROW_NUMBER() over (partition by name order by percentage desc) ROWNUM
from A
),
cte2 as
(
SELECT Id,Code,ROWNUM,' + @name_concat + ',' + @name1_concat + '
FROM cte
PIVOT(MAX(activity)
FOR name IN (' + @name_concat + ')) AS PVTTable PIVOT
(
MAX(percentage)
FOR name1 IN (' + @name1_concat + ')) AS PVTTable1
)
select Id, Code, ' + @select_aggs + '
from cte2
group by Id, Code, ROWNUM
'
exec sp_executesql @sql
Transpose / Pivot distinct row attribute as column and group another attribute?
You can use the PIVOT
function. If you have a known number of columns, then you can hard-code the values:
select *
from
(
select game, player, goals
from yourtable
) src
pivot
(
sum(goals)
for player in ([John], [Paul], [Mark], [Luke])
) piv
order by game
See SQL Fiddle with Demo
If you have an unknown number of columns, then you can use dynamic sql:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(player)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT game, ' + @cols + ' from
(
select game, player, goals
from yourtable
) x
pivot
(
sum(goals)
for player in (' + @cols + ')
) p '
execute(@query)
See SQL Fiddle with Demo
SQL Server Pivot - distinct values
You are very close, you would only have to add the pivoted fields to your SELECT list (and remove that DISTINCT, because the data is grouped automatically):
SELECT [Day], [Coke], [Pepsi], [Tango]
FROM [TABLE]
PIVOT (SUM([Cost]) FOR [Prod] IN ([Coke], [Pepsi], [Tango])) AS PIVOTSALES
But...
I hope that your table also has a primary key, and if so, this query will not work, since PIVOT not only creates columns for the values of the pivoted field (Prod
) that will contain values calculated using the value field (Cost
) but also does a GROUP BY
by all other columns contained in what is specified in the FROM clause. Therefore, if your table contains more than the mentionned 3 columns Day
, Prod
and Cost
, you will have to specify a subquery in the FROM clause (and give it an alias):
SELECT [Day], [Coke], [Pepsi], [Tango]
FROM (SELECT [Day], [Cost], [Prod] FROM [TABLE]) AS [Alias]
PIVOT (SUM([Cost]) FOR [Prod] IN ([Coke], [Pepsi], [Tango])) AS PIVOTSALES
Select distinct values across columns
One option is to UNPIVOT
your data and then PIVOT
via a dense_rank()
Example
Declare @YourTable Table ([ID] varchar(50),[Color1] varchar(50),[Color2] varchar(50),[Color3] varchar(50),[Color4] varchar(50))
Insert Into @YourTable Values
(1,'Red','Blue','Blue','Green')
Select *
From (
Select A.ID
,B.Item
,Col = concat('Color',dense_rank() over (partition by ID order by Item) )
from @YourTable A
Cross Apply ( values (color1)
,(color2)
,(color3)
,(color4)
) B(Item)
Where ID=1
) src
Pivot (max(item) for Col in (Color1,Color2,Color3,Color4) ) pvt
Returns
ID Color1 Color2 Color3 Color4
1 Blue Green Red NULL
Note: The Where ID=1
is optional
SQL Server : how to pivot where new columns have multiple unique values
Really you want an UNPIVOT
to take care of the multiple columns, then a PIVOT
to get your data. My favorite way of doing an UNPIVOT
is to use CROSS APPLY
, but you can do it however you want. Like such.
SELECT E, F, G
FROM (
SELECT CUST, ColumnName, Value
FROM Product
CROSS APPLY ( VALUES ('PRODUCT', PRODUCT),
('QTY', QTY),
('SMALLEST',SMALLEST))
UnPivoted(ColumnName, Value)) up
PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt
And of course if you want to see what column the values are coming from:
SELECT ColumnName, E, F, G
FROM (
SELECT CUST, ColumnName, Value
FROM Product
CROSS APPLY ( VALUES ('PRODUCT', PRODUCT),
('QTY', QTY),
('SMALLEST',SMALLEST))
UnPivoted(ColumnName, Value)) up
PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt
EDIT:
Here is a solution for multiple types. Basically you have to have do multiple queries, one for each data type. Among other things you have a SUM
in your numeric query that won't work on varchar columns. Your output also has to be all the same. Meaning you have to convert any numeric or date columns into varchar.
SELECT ColumnName, CAST(E AS varchar(30)) E, CAST(F AS varchar(30)) F, CAST(G AS varchar(30)) G
FROM (
SELECT CUST, ColumnName, Value
FROM Product
CROSS APPLY ( VALUES ('PRODUCT', PRODUCT),
('QTY', QTY),
('SMALLEST',SMALLEST))
UnPivoted(ColumnName, Value)) up
PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt
UNION ALL
SELECT ColumnName, E, F, G
FROM (
SELECT CUST, ColumnName, Value
FROM Product
CROSS APPLY ( VALUES ('CharColA', CharColA),
('CharColB', CharColB))
UnPivoted(ColumnName, Value)) up
PIVOT (MIN(VALUE) FOR CUST IN (E,F,G)) AS pvt
count and display distinct values in excel rows
You could do this by using the Data Model and creating measures to display text values within the Value field of a PivotTable, but I think Power Query would be more efficient.
Load your data into Power Query. Data tab in the Ribbon > From Table/Range
Select the Name column, right-click, Unpivot Other Columns
Select the Name and Value columns, right-click, Group By.
New Column name = "Count", Operation = "Count Rows", Column will be blank.
Select the Value and Count columns. Go to the Transform tab in the ribbon, select Merge Columns under the Text Column section. Use whatever seperator you want, I chose colon.
Right-click the Name column, select Group By. Name the column whatever you like, and do a Sum operation on your newly Merged column.
Your resulting column will have an error. In the formula bar replace this code:
= Table.Group(#"Merged Columns", {"name"}, {{"MergedRows", each List.Sum([Merged]), type text}})
With this code, replacing MergedRows with your column header.
= Table.Group(#"Merged Columns", {"name"}, {{"MergedRows", each Text.Combine([Merged],":"), type text}})
Notice how my Text.Combine separator is the same colon as I used earlier to merge columns. Now you can selected your fully merged column, and choose Split Column under the Transform tab in the ribbon. Choose delimiter and colon.
Now you just need to clean up the column order and headers.
Related Topics
How to Populate Calendar Table in Oracle
How to Copy a Huge Table Data into Another Table in SQL Server
Add Business Days to Date in SQL Without Loops
Rodbc Temporary Table Issue When Connecting to Ms SQL Server
How to Correctly Insert Newline in Nvarchar
SQL Performance: Where VS Where(Row_Number)
Ad Hoc Queries VS Stored Procedures VS Dynamic SQL
Error 1111 (Hy000): Invalid Use of Group Function
Count Returning Blank Instead of 0
How to Exclude Rows That Don't Join with Another Table
Return Multiple Columns and Rows from a Function Postgresql Instead of Record
Normalization in Plain English
Restrict an SQL Server Connection to a Specific Ip Address
Pass String Variable in R Script to Use It in SQL Statement
SQL Create Logon - Can't Use @Parameter as Username
Trim Trailing Spaces with Postgresql
Postgres Error: More Than One Row Returned by a Subquery Used as an Expression