我有一个工作查询,它按硬件模型和结果对数据进行分组,但问题是有很多“结果”。 我尝试将其减少到 “如果结果 = 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 中的方式聚合计数。
您的查询已经可以工作 - 除非您遇到命名冲突或只是将 输出列(
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
在同样的情况下会使得。这种不一致是为了 兼容SQL标准。GROUP BY
粗体强调我的。
可以通过在 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
,所以这是相当误导的。
Sum(CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END) as Count,
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
希望这有帮助。
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;
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;