SQL Query to Transpose Column Counts to Row Counts

本小妞迷上赌 提交于 2019-12-08 14:16:01

问题


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

回答1:


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




回答2:


Instead of using conditional aggregates, just use CASE to populate the Type appropriately then group on Type:

   ;with cte AS (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'
                          end as Type
                 From profile.foo)
    SELECT Type,COUNT(*) AS ct
    FROM cte
    GROUP BY Type

Not 100% on postgresql syntax, but the logic is compatible.




回答3:


I like to use the Postgres specific parallel unnest() for this:

SELECT unnest('{win2k,winxp,win2k3,vista,win7,win8,win8.1}'::text[]) AS type
      ,unnest(ARRAY[
          count(some_column ~ '5.0.2195' OR NULL)
         ,count(some_column ~ '5.1.2600' OR NULL)
          .. the rest from your query above ...
       ]) AS ct
FROM   profile.foo

Sequence and number of values in both arrays must match.
Related answers with more details (be sure to read up!):

  • Parallel unnest() and sort order in PostgreSQL

  • Is there something like a zip() function in PostgreSQL that combines two arrays?

Alternative counting technique (optional)

count() only counts non-null values..

(TRUE  OR NULL) IS TRUE  
(FALSE OR NULL) IS NULL  
(NULL  OR NULL) IS NULL

Voilá. Only TRUE is counted. More details in this answer on dba.SE.

Aside: Using ~ instead of ~* in the expressions, since there are no case sensitive letters in these string literals. But I doubt you need a regular expression match at all.

Also, the column names profile.foo don't make sense, since the only table is named foo, not profile



来源:https://stackoverflow.com/questions/25797850/sql-query-to-transpose-column-counts-to-row-counts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!