【问题标题】:How to use sum (case ... when ... then ...) properly?如何正确使用 sum (case ... when ... then ...)?
【发布时间】:2019-09-12 17:01:44
【问题描述】:

我想将具有特定值的行汇总为特定列。 早些时候我做了这样的事情:

SELECT date                                          AS 'Date',
   sum(CASE license_id WHEN 'a' THEN data.Amount ELSE 0 END) AS 'a',
   sum(CASE license_id WHEN 'b' THEN data.Amount ELSE 0 END) AS 'b',
   sum(
           CASE license_id WHEN '1' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '2' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '3' THEN data.Amount ELSE 0 END
       )                                                        AS 'c',
   sum(
           CASE license_id WHEN '10' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '11' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '12' THEN data.Amount ELSE 0 END
       )                                                        AS 'd'
FROM ...
...

这正是我想要的,但现在我有了一个新场景。 我需要总结不同的温度结果。以下代码不起作用,只是为了解释我想要的:

SELECT date                                          AS 'Date',
   sum(CASE license_id WHEN 'b' THEN data.Amount ELSE 0 END) AS 'b',
   sum(    CASE license_id WHEN '1' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '2' THEN data.Amount ELSE 0 END +
           CASE license_id WHEN '3' THEN data.Amount ELSE 0 END +
           b
       )                                                        AS 'c',
FROM ...
...

所以我的问题是因为这只是整个 SELECT 语句的一部分:

  • 我可以让CASE ... WHEN ... THEN ... + CASE ... WHEN ... THEN ... + CASE ... WHEN ... THEN ... 更简单吗?
  • 是否有可能实现我可以在进一步计算中使用临时结果?

提前感谢您的帮助!

【问题讨论】:

  • 能否提供表格结构、示例输入数据和示例结果行?每个案例末尾的+ 是做什么用的?
  • 首先,您可以删除部分ELSE 0,因为它默认为null,即未添加。
  • 使用一种情况,而不是把几种情况相加。
  • 另外,您可以使用IN,如CASE license_id IN ('1', '2', '3') THEN ...。
  • 您使用的是哪个DBMS 产品? “SQL”只是一种查询语言,而不是特定数据库产品的名称(并且您使用的是无效的标准 SQL)。请为您正在使用的数据库产品添加tag

标签: mysql sql innodb conditional-aggregation


【解决方案1】:

问题是 b 不被理解 - 或者充其量是对表中列的引用而不是您的表达式。

这是 SQL 的一般属性。您不能在同一查询的SELECT、FROM 或WHERE 子句中重复使用列别名。您在 MySQL 中基本上有三个选项:

  • 使用子查询
  • 重复表达式
  • 使用 CTE

这种情况下,其实还有第四种选择,因为重写查询简化了逻辑:

select date,
       sum(case license_id when 'b' then data.Amount else 0 end) AS b,
       sum(case when license_id in ('b', '1', '2', '3')  then data.Amount else 0 
           end) as c,
from ...

注意case 的形式有点不同,在when 之后是一个布尔条件。

此外,列别名不需要单引号。如果您想防止代码出现问题,请仅对字符串和日期常量使用单引号。

【讨论】:

  • "或 最好 引用列 ...",我会说相反,“或 最差 引用一列……”。
  • 非常感谢您的建议,但我担心这不会解决我的问题。是否可以有像 @var = ('1', '2', '3') 之类的变量?
  • @DerKnecht 。 . .这(以及其他答案)回答了您提出的问题。如果您有不同的问题,那么也许您应该将其作为 新 问题提出。
【解决方案2】:

由于您总是在测试 license_id 并且总是对 data.Amount 求和,因此 IN 条件可以为您节省大量输入:

 SELECT
      sum(CASE license_id WHEN 'a' THEN data.Amount END) AS a,
      sum(CASE license_id WHEN 'b' THEN data.Amount END) AS b,
      sum(CASE WHEN license_id IN ('b','1','2','3') THEN data.amount END) as c
      ...

您没有指定您使用的是哪个 RDBMS,但我敢打赌,如果它支持 CASE 表达式,那么它可能也支持 IN。

【讨论】:

  • 谢谢@TheImpaler 我已经摆脱了我的copypasta示例。
  • @TheImpaler,取决于您是否希望不存在的 license_id 为 0 或 null。
  • @TheImpaler, dbfiddle.uk/…
  • @jarlh 圣鳄梨酱。你说的对。我在 PostgreSQL、MariaDB、DB2、Oracle 和 MySQL 中测试了您的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多