Search code examples
sqlpostgresqlunpivotunnest

SQL Query to Transpose Column Counts to Row Counts


I have a table that looks like the following which shows the count of types. I need to and have been trying to display data as 1 column and 7 rows instead though... without success.

__________________________________________________________________________
| col types      | win2k | winxp | win2k3 | vista | win7 | win8 | win8.1 |
--------------------------------------------------------------------------
| count of types |  2365 | 65655 | 422445 | 4822  | 482  | 2331 | 485323 |
--------------------------------------------------------------------------
Select 
count(case when col1 ~* '5.0.2195' then 1 else null end) as Win2k,
count(case when col1 ~* '5.1.2600' then 1 else null end) as WinXP, 
count(case when col1 ~* '5.2.3790' then 1 else null end) as W2k3,
count(case when (col1 ~* '6.0.6000'
    or col1 ~* '6.0.6001' or col1 ~* '6.0.6002') 
    then 1 else null end) as Vista,
count(case when (col1 ~* '6.1.7600'
    or col1 ~* '6.1.7601')
    then 1 else null end) as Win7,
count(case when col1 ~* '6.2.9200' then 1 else null end) as Win8,
count(case when (col1 ~* '6.3.9200'
    or col1 ~* '6.3.9600')
    then 1 else null end) as "Win8.1"
From col1

Ideally it would look something like this:

___________________
| types  | count  |
-------------------
| win2k  | 2365   |
| winxp  | 65655  |
| win2k3 | 422445 | 
| vista  | 4822   |
| win7   | 482    |
| win8   | 2331   |
| win8.1 | 485323 |
-------------------

Notes:

  • I am using Postgresql 9.3 with PGADMIN III
  • I cannot create any custom functions
  • It wouldn't matter if there were more columns to make this work

Solution

  • These type of queries are easier to make with an aim of GROUP BY, like this:

    Select 
    case when profile.foo ~* '5.0.2195' then 'Win2k'
         when profile.foo ~* '5.1.2600' then 'WinXP' 
         when profile.foo ~* '5.2.3790' then 'W2k3'
         when (profile.foo ~* '6.0.6000'
            or profile.foo ~* '6.0.6001'
            or profile.foo ~* '6.0.6002') 
            then 'Vista'
         when (profile.foo ~* '6.1.7600'
            or profile.foo ~* '6.1.7601')
            then 'Win7'
         when profile.foo ~* '6.2.9200' then 'Win8'
         when (profile.foo ~* '6.3.9200'
            or profile.foo ~* '6.3.9600')
            then 'Win8.1' ELSE 'Other' END as type,
         count(*) as cnt
    From profile
    GROUP BY 1
    

    As commented below this query will work for mutually exclusive cases, i.e. when profile.foo contains a value representing one OS per row