PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

GROUP BY + CASE-Anweisung

Ihre Abfrage würde bereits funktionieren - außer dass Sie auf Namenskonflikte stoßen oder nur die Ausgabespalte verwirren (der CASE Ausdruck) mit Quellspalte result , die einen anderen Inhalt hat.

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

Sie müssen GROUP BY verwenden Ihr CASE Ausdruck anstelle Ihrer Quellspalte:

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

Oder geben Sie einen Spaltenalias an das unterscheidet sich von allen Spaltennamen in FROM list - oder diese Spalte hat Vorrang:

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

Der SQL-Standard ist in dieser Hinsicht ziemlich eigenartig. Zitieren Sie das Handbuch hier:

Der Name einer Ausgabespalte kann verwendet werden, um auf den Wert der Spalte in ORDER BY zu verweisen und GROUP BY -Klauseln, aber nicht im WHERE oder HAVING Klauseln; dort müssen Sie stattdessen den Ausdruck ausschreiben.

Und:

Wenn ein ORDER BY Ausdruck ist ein einfacher Name, der sowohl mit einem Ausgabespaltennamen als auch mit einem Eingabespaltennamen übereinstimmt, ORDER BY interpretiert ihn als den Namen der Ausgabespalte. Dies ist das Gegenteil von GROUP BY machen in der gleichen Situation. Diese Inkonsistenz soll mit dem SQL-Standard kompatibel sein.

Fett Hervorhebung von mir.

Diese Konflikte können durch Verwendung von Positionsreferenzen vermieden werden (Ordnungszahlen) in GROUP BY und ORDER BY , die Elemente in SELECT referenzieren Liste von links nach rechts. Siehe Lösung unten.
Der Nachteil ist, dass dies möglicherweise schwieriger zu lesen und anfällig für Änderungen im SELECT ist Liste (man könnte vergessen, Positionsreferenzen entsprechend anzupassen).

Aber Sie nicht muss die Spalte day hinzugefügt werden zu GROUP BY -Klausel, solange sie einen konstanten Wert enthält (CURRENT_DATE-1 ).

Umgeschrieben und vereinfacht mit der richtigen JOIN-Syntax und Positionsreferenzen könnte es so aussehen:

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;

Beachten Sie auch, dass ich den Spaltennamen time vermeide . Das ist ein reserviertes Wort und sollte niemals als Bezeichner verwendet werden. Außerdem ist Ihre "Zeit" offensichtlich ein timestamp oder date , das ist also ziemlich irreführend.