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=1
和case=1
(因为有很多“结果”值,我已经变成了0 = 0,其他都是1 )。 我希望那个被表示为1行,如在示例数据集2中聚合的计数。
您的查询将已经工作 – 除了您正在运行命名冲突或只是混淆输出列 ( CASE
expression式)与具有不同内容的源列 result
。
... GROUP BY model.name, attempt.type, attempt.result ...
您需要GROUP BY
您的CASE
expression式而不是源列:
... 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 BY
和GROUP BY
子句中的列值,但不能用于WHERE
或HAVING
子句中; 那么你必须写出expression式。
和:
如果
ORDER BY
expression式是与输出列名称和input列名称相匹配的简单名称,则ORDER BY
将把它解释为输出列名称。 这与GROUP BY
在相同情况下的select恰恰相反 。 这种不一致是与SQL标准兼容的。
大胆重视我的。
这些冲突可以通过在GROUP BY
和ORDER 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
。 这是一个保留字 ,不能用作标识符。 此外,你的“时间”显然是一个timestamp
或date
,所以这是相当具有误导性的。
你可以请尝试这个:用下面的一个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;