PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Istruzione GROUP BY + CASE

La tua query funzionerebbe già, tranne per il fatto che stai riscontrando conflitti di denominazione o semplicemente confondendo la colonna di output (il CASE espressione) con colonna sorgente result , che ha contenuti diversi.

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

Devi GROUP BY il tuo CASE espressione invece della colonna di origine:

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

Oppure fornisci un alias di colonna è diverso da qualsiasi nome di colonna nel FROM list - oppure quella colonna ha la precedenza:

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

Lo standard SQL è piuttosto peculiare a questo riguardo. Citando il manuale qui:

Il nome di una colonna di output può essere utilizzato per fare riferimento al valore della colonna inORDER BY e GROUP BY clausole, ma non in WHERE o HAVING clausole; lì devi invece scrivere l'espressione.

E:

Se un ORDER BY espressione è un nome semplice che corrisponde sia a un nome di colonna di output che a un nome di colonna di input, ORDER BY lo interpreterà come il nome della colonna di output. Questo è l'opposto della scelta che GROUP BY farà nella stessa situazione. Questa incoerenza è resa compatibile con lo standard SQL.

Grassetto enfasi mia.

Questi conflitti possono essere evitati utilizzando riferimenti posizionali (numeri ordinali) in GROUP BY e ORDER BY , facendo riferimento agli elementi in SELECT elenco da sinistra a destra. Vedi la soluzione di seguito.
Lo svantaggio è che potrebbe essere più difficile da leggere e vulnerabile alle modifiche nel SELECT list (si potrebbe dimenticare di adattare i riferimenti posizionali di conseguenza).

Ma tu non aggiungere la colonna day al GROUP BY clausola, purché contenga un valore costante (CURRENT_DATE-1 ).

Riscritto e semplificato con una corretta sintassi JOIN e riferimenti posizionali potrebbe apparire così:

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;

Nota anche che sto evitando il nome della colonna time . Questa è una parola riservata e non dovrebbe mai essere usata come identificatore. Inoltre, il tuo "tempo" ovviamente è un timestamp o date , quindi è piuttosto fuorviante.