如何使用 CASE 语句而不必将其放入 GROUP BY

Posted

技术标签:

【中文标题】如何使用 CASE 语句而不必将其放入 GROUP BY【英文标题】:How to use CASE statement without having to put it into GROUP BY 【发布时间】:2015-12-01 02:08:30 【问题描述】:

我的查询有问题。这是我的代码:

select kpidate,reviewer as namareviewer, 
    count(formcode) as actual,
    round((0.2*count(formcode))) as target,
    CASE WHEN blibliknowledge !='' 
         THEN count(blibliknowledge)  
    END as blibli, 
    CASE WHEN solusi !=''
         THEN count(solusi)
    END as solusi
from kpi 
where kpidate >= '30/11/2015' AND kpidate<= '1/12/2015'
group by reviewer,kpidate,blibliknowledge,solusi

由于CASE 表达式,我必须添加列blibliknowledgesolusi,输出将是这样的:

我想按namareviewer 分组,所以'elbert.lukman' 将被分组。所以输出只有两行。 bliblisolusi 列也将被计算为按 namareviewer 分组

【问题讨论】:

mysql还是postgresql相关的问题? @Shadow 我认为两者之间的查询语言是一样的。不是吗? @Shieryn:类似,但远不一样。 Postgres 更接近标准 SQL。 【参考方案1】:

您似乎想要进行条件聚合。根据条件使用返回 1 或 0 的表达式,然后将其包装在 SUM 聚合中。或者,让表达式返回 NULL 和非 null 值,并将其包装在 COUNT 表达式中。

在 MySQL 中,日期文字应以 'yyyy-mm-dd' 格式提供。

举个例子:

SELECT k.kpidate
     , k.reviewer                                               AS namareviewer
     , COUNT(k.formcode)                                        AS actual
     , ROUND((0.2*COUNT(k.formcode)))                           AS target
     , SUM(CASE WHEN k.blibliknowledge != '' THEN 1 ELSE 0 END) AS blibli
     , COUNT(CASE WHEN k.solusi != '' THEN 'foo' ELSE NULL END) AS solusi
  FROM kpi k
 WHERE k.kpidate >= '2015-11-30'
   AND k.kpidate <= '2015-12-01'
 GROUP
    BY k.reviewer
     , k.kpidate

在 MySQL 中,我们可以用布尔表达式简写 CASE 表达式。如果表达式计算结果为 TRUE,MySQL 返回整数值 1,如果表达式计算结果为 FALSE,则返回 0。如果表达式的计算结果为 NULL,则返回 NULL。

SELECT k.kpidate
     , k.reviewer                              AS namareviewer
     , COUNT(k.formcode)                       AS actual
     , ROUND((0.2*COUNT(k.formcode)))          AS target
     , IFNULL(SUM(k.blibliknowledge != ''),0)  AS blibli
     , IFNULL(SUM(k.solusi          != ''),0)  AS solusi
  FROM kpi k
 WHERE k.kpidate >= '2015-11-30'
   AND k.kpidate <= '2015-12-01'
 GROUP
    BY k.reviewer
     , k.kpidate

【讨论】:

【参考方案2】:

您也可以缩短 Postgres 中的语法。这适用于 Postgres 和 MySQL:

SELECT kpidate
     , reviewer                             AS namareviewer
     , count(formcode)                      AS actual
     , round(count(formcode) * 0.2)         AS target
     , count(blibliknowledge <> '' OR NULL) AS blibli
     , count(solusi <> '' OR NULL)          AS solusi
FROM   kpi
WHERE  kpidate >= '2015-11-30'
AND    kpidate <  '2015-12-01'  -- typically, you'd exclude that upper bound
GROUP  BY reviewer, kpidate;

在 Postgres 9.4 中,您可以使用聚合 FILTER 子句的 SQL 标准实现:

SELECT kpidate
     , reviewer                                      AS namareviewer
     , count(formcode)                               AS actual
     , round(count(formcode) * 0.2)                  AS target
     , count(*) FILTER (WHERE blibliknowledge <> '') AS blibli
     , count(*) FILTER (WHERE solusi <> '')          AS solusi
FROM   kpi
WHERE  kpidate >= '2015-11-30'
AND    kpidate <  '2015-12-01'  -- typically, you'd exclude that upper bound
GROUP  BY 1, 2;  -- another optional syntax shortcut

还演示了一种语法简写,当您实际上必须在 SELECT 列表中引用一个较长的表达式时 - 也可以回答您的原始问题。

更多:

Conditional SQL count Concatenate multiple result rows of one column into one, group by another column

【讨论】:

以上是关于如何使用 CASE 语句而不必将其放入 GROUP BY的主要内容,如果未能解决你的问题,请参考以下文章

我如何将case语句放入javascript中的循环中

我如何告诉 gcc 在 switch/case 语句上警告(或失败)而不中断?

如何使用 IF 或 Case 函数来汇总 GROUP_CONCAT 列?然后将其应用于原始数据表?

在带有 LIKE 的 CASE 语句中使用 GROUP_CONCAT 列别名

Oracle SQL - 使用 CASE WHEN 语句时 GROUP BY 无效

带有表连接、case 语句、计数、group by 子句的 Linq 查询