52

我有一个工作查询,它​​按硬件模型和结果对数据进行分组,但问题是有很多“结果”。我试图将其减少到“如果结果 = 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会有所不同。简而言之,对于任何给定的模型,每个“类型 + 案例”组合我只需要 1 行。正如您在第一个结果集中看到的那样,我有 3 行modelA具有type=1case=1(因为有许多“结果”值我已经变成0=0 和其他任何值=1)。我希望将其表示为 1 行,并在示例数据集 2 中聚合计数。

4

5 回答 5

86

您的查询已经可以工作了 - 除了您遇到命名冲突或只是将输出列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 BYandGROUP BY子句中引用列的值,但不能在WHEREorHAVING子句中;在那里你必须写出表达式。

和:

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

大胆强调我的。

这些冲突可以通过在 和 中使用位置引用(序数)来避免,从左到右引用列表中的项目。请参阅下面的解决方案。 缺点是,这可能更难阅读并且容易受到列表中的编辑的影响(人们可能会忘记相应地调整位置引用)。GROUP BYORDER BYSELECT
SELECT

但是您不必列添加dayGROUP 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;

另请注意,我避免使用 column name time。这是一个保留字,不应该用作标识符。此外,您的“时间”显然是一个timestampordate,所以这是相当误导的。

于 2013-11-08T00:31:43.840 回答
15

你能试试这个:用下面的替换case语句

Sum(CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END) as Count,
于 2015-11-03T20:57:21.867 回答
4

只有在前面的步骤中引入了别名,才能使用它们。所以子句中的别名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

希望这可以帮助。

于 2020-04-19T07:11:42.540 回答
2

对于 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;
于 2017-03-30T14:40:16.673 回答
1

尝试将另外两个非 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;
于 2013-11-07T23:44:50.930 回答