Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pivot with an indefinite amount of distinct values

Tags:

sql

sql-server

I have written this query:

SELECT s, [1] AS a1, [2] AS a2, [3] AS a3, [4] AS a4
FROM (SELECT grade, aid, s FROM m) p
PIVOT
(
SUM(grade)
FOR aid IN ([1], [2], [3], [4])
) AS pvt ORDER BY pvt.s;

That returns the result:

s  a1  a2  a3  a4
1  25  69  95  56
2  27  99  16  87
. . . .
99 98  12  34  76

Which is exactly the result I want. My problem is that there will not always be four distinct values in 'aid'. Is it possible to rewrite this query (or use a stored procedure) so that the amount of 'a*' columns depends on how many distinct values are in 'aid'?

like image 533
vera miles Avatar asked May 29 '12 16:05

vera miles


People also ask

Can you Count only unique values in a pivot table?

In the Value Field Settings dialog, click Summarize Values By tab, and then scroll to click Distinct Count option, see screenshot: 5. And then click OK, you will get the pivot table which count only the unique values.

How does distinct Count work in Excel pivot?

By default, a Pivot Table will count all records in a data set. To show a unique or distinct count in a pivot table, you must add data to the object model when the pivot table is created. In the example shown, the pivot table displays how many unique colors are sold in each state.

How do I count unique values in SQL?

The COUNT DISTINCT function returns the number of unique values in the column or expression, as the following example shows. SELECT COUNT (DISTINCT item_num) FROM items; If the COUNT DISTINCT function encounters NULL values, it ignores them unless every value in the specified column is NULL.


2 Answers

You will need to use a Dynamic Pivot to get the list of columns that you want. This will retrieve the list of columns first and then pivot that list. Something similar to this:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(aid) 
            FROM m 
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT s, ' + @cols + ' from 
            (
                select grade, aid, s
                from m
           ) x
            pivot 
            (
                sum(grade)
                for aid in (' + @cols + ')
            ) p 
            ORDER BY p.s'

execute(@query)
like image 194
Taryn Avatar answered Oct 22 '22 22:10

Taryn


Lamak: Here is how I did it with column aliases. The alias is linked to the value from a column in another table that is linked by `aid'.

DECLARE
    @cols AS NVARCHAR(MAX),
    @colsAlias AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(aid) 
    FROM m
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')

SELECT @colsAlias = STUFF((SELECT DISTINCT ',' + QUOTENAME(m.aid) + ' AS ' + QUOTENAME(n.aName)  
    FROM m INNER JOIN n ON m.aid = n.aid
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')

SET @query = 'SELECT s, ' + @colsAlias + ' FROM 
                (
                SELECT grade, aid, s
                    FROM m
                ) x

            PIVOT 
            (
                MIN(grade) FOR aid IN (' + @cols + ')
            ) p '

EXECUTE(@query)
like image 41
vera miles Avatar answered Oct 22 '22 23:10

vera miles