将列计数转换为行计数的SQL查询

将列计数转换为行计数的SQL查询,sql,postgresql,unpivot,unnest,Sql,Postgresql,Unpivot,Unnest,我有一个表,它显示了类型的计数,如下所示。我需要并且一直在尝试将数据显示为1列和7行,但是。。。没有成功 理想情况下,它看起来像这样: 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 ~* '

我有一个表,它显示了类型的计数,如下所示。我需要并且一直在尝试将数据显示为1列和7行,但是。。。没有成功

理想情况下,它看起来像这样:

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
注:

我正在使用带有PGADMIN III的Postgresql 9.3 我无法创建任何自定义函数 如果有更多的专栏来完成这项工作,那也没关系
我喜欢使用Postgres特定的并行unnest:

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
两个数组中的值的顺序和数量必须匹配。 请务必仔细阅读更多详细信息的相关答案!:

可选的替代计数技术 计数仅计数非空值

(TRUE  OR NULL) IS TRUE  
(FALSE OR NULL) IS NULL  
(NULL  OR NULL) IS NULL
瞧。只有真的才算数

旁白:在表达式中使用,因为这些字符串文本中没有区分大小写的字母。但我怀疑您是否需要正则表达式匹配


此外,列名profile.foo没有意义,因为唯一的表名为foo,而不是profile

这些类型的查询更容易进行分组,如下所示:

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

如下文所述,此查询适用于互斥情况,即当profile.foo包含表示每行一个操作系统的值时,而不是使用条件聚合,只需使用CASE适当填充类型,然后按类型分组:


postgresql语法不是100%,但逻辑是兼容的。

我认为Bulat的可能重复是正确的,您想要一个与Bulat相反的unpivot表,我在发布之前查看并尝试了该引用,尽管它看起来可能类似,但它有一个不同的表/数据结构,不适用。我的单数行是聚合数据,这使得取消PIVOT非常困难,如果不是不可能的话。当然这是可能的。您提出的查询是非法且令人困惑的,因此很难说什么最适合您。profile.foo在查询上下文中不是合法的列名。请回答这个问题。你可以提供表格定义和一些示例值来澄清。。。仍在学习中。CASE语句每行正好生成1个匹配项,而在原始查询中,每行可以匹配多个表达式。Q列中的列名非法。可能不是作者的本意,但仍然可能有不同的结果。我运行了此操作并获得:错误:架构配置文件不存在第9行:From profile.flavor^*************错误**********错误:架构配置文件不存在SQL状态:3F000字符:914@ErwinBrandstetter原始查询中的CASE语句之间没有任何条件重叠,因此,计数将等同于我在这里所做的,就像行而不是列一样,当然除了语法问题。@BooneStars我不知道是什么导致了这个错误,我不太熟悉postgresql语法。这是一个逻辑错误。条件不必重叠。单个字符串可以匹配任意数量的正则表达式,特别是因为它们没有锚定。考虑值“5.0.2195 5.1.2600”。我现在把这个扔了。在from语句中,我删除了列名,它工作得非常好。谢谢正如对另一个同等问题和先前问题的评论,该答案仅适用于相互排斥的情况。用分组1简化。@ErwinBrandstetter:谢谢你的评论。我做了一个编辑,反映了你的评论。顺便说一句,如果profile.foo中有多个值,那么可以使用UNION ALLUNION ALL执行计数,是的,但是由于多个顺序扫描,成本要高得多。
(TRUE  OR NULL) IS TRUE  
(FALSE OR NULL) IS NULL  
(NULL  OR NULL) IS NULL
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
   ;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