GROUP BY + CASE语句

我有一个工作查询是按硬件模型和结果分组数据,但问题是有很多“结果” 。 我试图减less到“如果结果= 0,然后保持为0,否则将其设置为1” 。 这一般工作,但我最终有:

day | name | type | case | count ------------+----------------+------+------+------- 2013-11-06 | modelA | 1 | 0 | 972 2013-11-06 | modelA | 1 | 1 | 42 2013-11-06 | modelA | 1 | 1 | 2 2013-11-06 | modelA | 1 | 1 | 11 2013-11-06 | modelB | 1 | 0 | 456 2013-11-06 | modelB | 1 | 1 | 16 2013-11-06 | modelB | 1 | 1 | 8 2013-11-06 | modelB | 3 | 0 | 21518 2013-11-06 | modelB | 3 | 1 | 5 2013-11-06 | modelB | 3 | 1 | 7 2013-11-06 | modelB | 3 | 1 | 563 

而不是我试图实现的聚合,每个types/案例组合只有1行。

  day | name | type | case | count ------------+----------------+------+------+------- 2013-11-06 | modelA | 1 | 0 | 972 2013-11-06 | modelA | 1 | 1 | 55 2013-11-06 | modelB | 1 | 0 | 456 2013-11-06 | modelB | 1 | 1 | 24 2013-11-06 | modelB | 3 | 0 | 21518 2013-11-06 | modelB | 3 | 1 | 575 

这是我的查询:

 select CURRENT_DATE-1 AS day, model.name, attempt.type, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END, count(*) from attempt attempt, prod_hw_id prod_hw_id, model model where time >= '2013-11-06 00:00:00' AND time < '2013-11-07 00:00:00' AND attempt.hard_id = prod_hw_id.hard_id AND prod_hw_id.model_id = model.model_id group by model.name, attempt.type, attempt.result order by model.name, attempt.type, attempt.result; 

任何提示,我如何能达到这个将是真棒。

日将始终在WHERE子句中定义,所以不会有所不同。 name, type, result(case)count会有所不同。 总之,对于任何给定的模型,我只需要每行“types+大小写”组合。 正如你在第一个结果集中可以看到的,我有3行modelA ,它们的type=1case=1 (因为有很多“结果”值,我已经变成了0 = 0,其他都是1 )。 我希望那个被表示为1行,如在示例数据集2中聚合的计数。

您的查询将已经工作 – 除了您正在运行命名冲突或只是混淆输出列CASEexpression式)与具有不同内容的源列 result

 ... GROUP BY model.name, attempt.type, attempt.result ... 

您需要GROUP BY您的CASEexpression式而不是源列:

 ... GROUP BY model.name, attempt.type , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END ... 

或者提供与FROM列表中的任何列名称不同的列别名 – 否则该列优先:

 SELECT ... , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END AS result1 ... GROUP BY model.name, attempt.type, result1 ... 

SQL标准在这方面相当奇特。 在这里引用手册:

输出列的名称可用于引用ORDER BYGROUP BY子句中的列值,但不能用于WHEREHAVING子句中; 那么你必须写出expression式。

和:

如果ORDER BYexpression式是与输出列名称和input列名称相匹配的简单名称,则ORDER BY将把它解释为输出列名称。 这与GROUP BY在相同情况下的select恰恰相反 。 这种不一致是与SQL标准兼容的。

大胆重视我的。

这些冲突可以通过在GROUP BYORDER BY使用位置引用 (序号)来避免,从左到右引用SELECT列表中的项目。 见下面的解决scheme
缺点是,这可能难以阅读,容易受到SELECT列表中的编辑(人们可能忘记相应地调整位置参考)。

但是,您不必将列day添加到GROUP BY子句,只要它保持一个常量值( CURRENT_DATE-1 )即可。

用适当的JOIN语法和位置引用来重写和简化它可能看起来像这样:

 SELECT m.name , a.type , CASE WHEN a.result = 0 THEN 0 ELSE 1 END AS result , CURRENT_DATE - 1 AS day , count(*) AS ct FROM attempt a JOIN prod_hw_id p USING (hard_id) JOIN model m USING (model_id) WHERE ts >= '2013-11-06 00:00:00' AND ts < '2013-11-07 00:00:00' GROUP BY 1,2,3 ORDER BY 1,2,3; 

另外请注意,我正在避免列名称的time 。 这是一个保留字 ,不能用作标识符。 此外,你的“时间”显然是一个timestampdate ,所以这是相当具有误导性的。

你可以请尝试这个:用下面的一个replace案例陈述

 Sum(CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END) as Count, 

尝试将另外两个非COUNT列添加到GROUP BY:

 select CURRENT_DATE-1 AS day, model.name, attempt.type, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END, count(*) from attempt attempt, prod_hw_id prod_hw_id, model model where time >= '2013-11-06 00:00:00' AND time < '2013-11-07 00:00:00' AND attempt.hard_id = prod_hw_id.hard_id AND prod_hw_id.model_id = model.model_id group by 1,2,3,4 order by model.name, attempt.type, attempt.result; 

对于TSQL,我喜欢在外部应用中封装case语句。 这样可以防止我必须写两次case语句,允许在以后的连接中通过别名引用case语句,并避免需要位置引用。

 select oa.day, model.name, attempt.type, oa.result COUNT(*) MyCount FROM attempt attempt, prod_hw_id prod_hw_id, model model WHERE time >= '2013-11-06 00:00:00' AND time < '2013-11-07 00:00:00' AND attempt.hard_id = prod_hw_id.hard_id AND prod_hw_id.model_id = model.model_id OUTER APPLY ( SELECT CURRENT_DATE-1 AS day, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END result ) oa group by oa.day, model.name, attempt.type, oa.result order by model.name, attempt.type, oa.result;