GROUP BY 和 ORDER BY 中的列名称

问题描述 投票:0回答:5

我有一个工作查询,它按硬件模型和结果对数据进行分组,但问题是有很多“结果”。 我尝试将其减少到 “如果结果 = 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

而不是我试图实现的聚合,其中每个类型/案例组合只有 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;

任何关于我如何实现这一目标的提示都很棒。

Day 将始终在

WHERE
子句中定义,因此不会变化。
name, type, result(case)
count
会有所不同。简而言之,对于任何给定的模型,我只需要每个 “type + case” 组合 1 行。正如你在第一个结果集中看到的,我有 3 行
modelA
,其中有
type=1
case=1
(因为有很多 "result" 值我已经变成了 0=0 和其他= 1)。我希望将其表示为 1 行,并按照示例数据集 2 中的方式聚合计数。

sql postgresql group-by case aggregate-functions
5个回答
105
投票

您的查询已经可以工作 - 除非您遇到命名冲突或只是将 输出列

CASE
表达式)与源列
result
混淆,后者具有不同的内容。

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

您需要

GROUP BY
您的
CASE
表达式而不是源列:

...
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
子句中; 在那里你必须写出表达式。

并且:

如果

ORDER BY
表达式是一个与输出匹配的简单名称 列名称和输入列名称,
ORDER BY
将其解释为 输出列名称。 这与选择相反
GROUP BY
在同样的情况下会使得
。这种不一致是为了 兼容SQL标准。

粗体强调我的。

可以通过在 GROUP BY

ORDER BY
中使用
位置引用
(序数),从左到右引用
SELECT
列表中的项目来避免这些冲突。请参阅下面的解决方案。
缺点是这可能更难阅读并且容易受到
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
,所以这是相当误导的。


18
投票

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



6
投票
SELECT

子句中的别名可以在

ORDER BY
中使用,但不能在
GROUP BY
子句中使用。

参考:Microsoft T-SQL 文档以供进一步阅读。

FROM ON JOIN WHERE GROUP BY WITH CUBE or WITH ROLLUP HAVING SELECT DISTINCT ORDER BY TOP

希望这有帮助。


2
投票

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;



2
投票

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;

	
© www.soinside.com 2019 - 2024. All rights reserved.