PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Инструкция GROUP BY + CASE

Заявката ви вече ще работи - освен че се сблъсквате с конфликти с имена или просто обърквате изходната колона (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 , така че това е доста подвеждащо.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Грешка при настройка на n_distinct с помощта на променлива plpgsql

  2. Свържете се с база данни PostgreSQL в Docker контейнер

  3. Референтна стойност на серийната колона в друга колона по време на същото INSERT

  4. Незадължителен израз INSERT във веригата на транзакции, използвайки NodeJS и Postgres

  5. Изцяло игнориране на часовите зони в Rails и PostgreSQL