sql >> Databáze >  >> RDS >> PostgreSQL

Příkaz GROUP BY + CASE

Váš dotaz by již fungoval – až na to, že se dostáváte do konfliktů názvů nebo si jen pletete výstupní sloupec (CASE výraz) se zdrojovým sloupcem result , která má jiný obsah.

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

Musíte GROUP BY váš CASE výraz místo vašeho zdrojového sloupce:

...
GROUP BY model.name, attempt.type
       , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END
...

Nebo zadejte alias sloupce který se liší od názvu kteréhokoli sloupce v FROM seznam – jinak má tento sloupec přednost:

SELECT ...
     , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END AS result1
...
GROUP BY model.name, attempt.type, result1
...

Standard SQL je v tomto ohledu poněkud zvláštní. Zde cituji manuál:

Název výstupního sloupce lze použít jako odkaz na hodnotu sloupce vORDER BY a GROUP BY klauzule, ale ne v WHERE nebo HAVING klauzule; tam musíte místo toho napsat výraz.

A:

Pokud ORDER BY výraz je jednoduchý název, který odpovídá názvu výstupního sloupce i názvu vstupního sloupce, ORDER BY bude to interpretovat jako název výstupního sloupce. Toto je opak volby GROUP BY udělá ve stejné situaci. Tato nekonzistence je navržena tak, aby byla kompatibilní se standardem SQL.

Tučné zdůrazněte můj.

Těmto konfliktům se lze vyhnout pomocí pozičních referencí (řadová čísla) v GROUP BY a ORDER BY , odkazující na položky v SELECT seznam zleva doprava. Viz řešení níže.
Nevýhodou je, že to může být hůře čitelné a náchylné na úpravy v SELECT seznam (možná zapomenete odpovídajícím způsobem upravit poziční reference).

Ale vy ne musíte přidat sloupec day do GROUP BY klauzule, pokud má konstantní hodnotu (CURRENT_DATE-1 ).

Přepsané a zjednodušené se správnou syntaxí JOIN a pozičními odkazy by to mohlo vypadat takto:

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;

Všimněte si také, že se vyhýbám názvu sloupce time . Toto je vyhrazené slovo a nikdy by se nemělo používat jako identifikátor. Kromě toho, váš "čas" je samozřejmě timestamp nebo date , takže je to spíše zavádějící.



  1. Jak vrátit aktuální hodnotu rowversion pro databázi SQL Server (příklad T-SQL)

  2. SQL index DROP, tabulka DROP a příkazy databáze DROP vysvětlené s příklady

  3. Chyba MYSQLi:Uživatel již má aktivních připojení více než 'max_user_connections'

  4. Volitelný příkaz INSERT v řetězci transakcí pomocí NodeJS a Postgres