【问题标题】:Using CASE for a pivot-like function in SQL Server and Postgresql在 SQL Server 和 Postgresql 中将 CASE 用于类似枢轴的函数
【发布时间】:2019-03-08 22:30:55
【问题描述】:

我正在尝试创建一个简单的类似于数据透视表的报表,我设法使用 SQL Server 的 pivot 完成了该报表,但现在 SQL 需要在 SQL Server 和 Postgresql 上运行。

所以,我已将 SQL 更改为使用 CASE,如下所示:

SELECT SPACENAME
     , CASE WHEN PERMTYPE='VIEWSPACE' THEN 'X' END AS "Read Access"
     , CASE WHEN PERMTYPE='EDITSPACE' THEN 'X' END AS "Write Access"
FROM ( ...) sub
GROUP BY SPACENAME, PERMTYPE
ORDER BY SPACENAME

“...”是复杂子查询所在的位置,其输出为:

SPACENAME               PERMTYPE
Testware Releases       EDITSPACE
Testware Releases       VIEWSPACE
Documentation           VIEWSPACE

我正在尝试获取如下报告:

SPACENAME          Read Access  Write Access
Testware Releases       X           X
Documentation           X    

但我得到的是:

SPACENAME          Read Access  Write Access
Testware Releases                   X
Testware Releases       X   
Documentation           X

我在这里的另一个示例上构建了我的CASEPostgreSQL crosstab() alternative with CASE and aggregates)

只有两个区别:

  1. 另一个答案只在GROUP BY 中放置一列。我同意这是有道理的,但是当我这样做时,我得到一个错误:Column 'sub.PERMTYPE' 在选择列表中是无效的,因为它既不包含在聚合函数或 GROUP BY 子句中。
  2. 另一个答案在CASE 中使用sum()。如果我这样做(连同GROUP BY 中的单列),我可以让它工作,但它会显示一个基于数字的报告,但我真的只想要右列中的“X”...

有什么方法可以让列中的 X 而不是数字?

【问题讨论】:

    标签: sql sql-server postgresql


    【解决方案1】:

    最大化 CASE,然后在 SPACENAME 上分组

    SELECT SPACENAME
         , MAX(CASE WHEN PERMTYPE='VIEWSPACE' THEN 'X' ELSE '' END) AS "Read Access"
         , MAX(CASE WHEN PERMTYPE='EDITSPACE' THEN 'X' ELSE '' END) AS "Write Access"
    FROM ( <<your big sub-query>> ) sub
    GROUP BY SPACENAME
    ORDER BY SPACENAME
    

    【讨论】:

    • 完美运行,谢谢!关于为什么 MAX 在这里做正确的事情有什么解释吗?我现在在想,像这样的枢轴式报告中不在GROUP BY 中的所有内容都必须是类似数学的函数,而MAX 是唯一也可以处理字符串的类似数学的函数?
    • 这并不是什么魔法,也不是什么复杂的数学运算。 MAX 取最大值。并且 'X' 大于空字符串或 null。如果您在没有 GROUP BY 和 MAX 的情况下运行它,那么查看这些结果并想象它会将它们压缩到按字母顺序排列的最高值。如果您在 CASE 中返回数字,它将是最高数值
    • 聚合函数 AVG、SUM 期望的数字与人们期望的一样。但 MAX、MIN、COUNT、STRING_AGG 等函数适用于大多数类型。
    • 谢谢。那么,我的假设是否正确,即在顶级 SELECT 中返回的每个项目,即在 GROUP BYnot 必须是这些数学/聚合函数之一?这就是为什么我必须在GROUP BY 中包含我的“访问”列(它提供了太多行),或者对它们使用数学/聚合函数?
    • 答案是:it depends。对于大多数 RDBMS 版本,该假设是正确的。
    【解决方案2】:

    您希望答案按 Spacename 和您的 2 个别名列分组吗?

    在 SQL Server 中你可以尝试类似的方法:

    SELECT SPACENAME,Read Access,Write Access
    FROM
    (
      SELECT SPACENAME
         , CASE WHEN PERMTYPE='VIEWSPACE' THEN 'X' END AS "Read Access"
         , CASE WHEN PERMTYPE='EDITSPACE' THEN 'X' END AS "Write Access"
    FROM ( ...) --i do not have a way to duplicate your situation
    ) as sub2
    GROUP BY SPACENAME,Read Access,Write Access
    

    【讨论】:

    • 有趣的想法,但是通过将单独的“访问”列放在顶级GROUP BY 中,它仍然使数据以单独的行出现。如果将它们排除在外,则会回到旧错误:“列 'sub2.Read Access' 在选择列表中无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中
    • 我认为您想按别名进行分组,我无法完全按照您的情况进行测试,但也许您可以在这里找到一组更好的示例:stackoverflow.com/questions/3841295/sql-using-alias-in-group-by
    猜你喜欢
    • 2010-12-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多