Подтвердить что ты не робот

Операция GROUP BY + CASE

У меня есть рабочий запрос, который группирует данные по модели оборудования и результат, но проблема в том, что существует множество "результатов". Я попытался уменьшить это до "if result = 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;

Любые советы о том, как я могу достичь этого, будут потрясающими.

День всегда будет определяться в предложении WHERE, поэтому он не будет меняться. name, type, result(case) и count будут отличаться. Короче говоря, для любой данной модели я хочу только 1 строку на комбинацию "тип + случай". Как вы можете видеть в первом наборе результатов, у меня есть 3 строки для modelA, которые имеют type=1 и case=1 (потому что есть много значений "результата", которые я превратил в 0 = 0 и все остальное = 1). Я хочу, чтобы это было представлено как 1 строка с подсчетом, объединенным, как в примере набора данных 2.

4b9b3361

Ответ 1

Ваш запрос будет работать уже, за исключением того, что вы используете конфликты имен или просто путаете столбцы вывода (выражение 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, поэтому оно довольно вводит в заблуждение.

Ответ 2

можете ли вы попробовать следующее: замените оператор case ниже на

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

Ответ 3

Попробуйте добавить два других столбца не 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;

Ответ 4

Для 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;