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

Auswählen mehrerer max()-Werte mit einer einzigen SQL-Anweisung

Auch hier empfehle ich für mehr als nur ein paar "Datentypen" die Verwendung von crosstab() :

SELECT * FROM crosstab(
     $$SELECT DISTINCT ON (1, 2)
              'max' AS "type", data_type, val
       FROM   tbl
       ORDER  BY 1, 2, val DESC$$

    ,$$VALUES ('Final Fantasy'), ('Quake 3'), ('World of Warcraft')$$)
AS x ("type" text, "Final Fantasy" int, "Quake 3" int, "World of Warcraft" int)

Rückgabe:

type | Final Fantasy | Quake 3 | World of Warcraft
-----+---------------+---------+-------------------
max  | 500           | 1500    |    1200

Weitere Erläuterungen zu den Grundlagen:
PostgreSQL-Kreuztabellenabfrage

Dynamische Lösung

Das Schwierige ist, dies vollständig dynamisch zu machen :damit es funktioniert für

  • eine unbekannte Nummer von Spalten (in diesem Fall data_types)
  • mit unbekannten Namen (erneut data_types)

Zumindest der Typ ist bekannt:integer in diesem Fall.

Kurz gesagt:Das ist mit aktuellem PostgreSQL (einschließlich 9.3) nicht möglich. Es gibt Annäherungen mit polymorphen Typen und Möglichkeiten, die Einschränkungen mit Arrays oder hstore-Typen zu umgehen. Kann gut genug für dich sein. Aber es ist streng nicht möglich um das Ergebnis mit einzelnen Spalten in einer einzigen SQL-Abfrage zu erhalten. SQL ist sehr streng in Bezug auf Typen und möchte wissen, was zurück zu erwarten ist.

Allerdings , es kann mit zwei gemacht werden Abfragen. Der erste erstellt die tatsächlich zu verwendende Abfrage. Aufbauend auf dem obigen einfachen Fall:

SELECT $f$SELECT * FROM crosstab(
     $$SELECT DISTINCT ON (1, 2)
              'max' AS "type", data_type, val
       FROM   tbl
       ORDER  BY 1, 2, val DESC$$

    ,$$VALUES ($f$     || string_agg(quote_literal(data_type), '), (') || $f$)$$)
AS x ("type" text, $f$ || string_agg(quote_ident(data_type), ' int, ') || ' int)'
FROM  (SELECT DISTINCT data_type FROM tbl) x

Dadurch wird die Abfrage generiert, die Sie tatsächlich benötigen. Führen Sie die zweite in derselben Transaktion aus um Parallelitätsprobleme zu vermeiden.

Beachten Sie die strategische Verwendung von quote_literal() und quote_ident() um alle Arten illegaler (für Spalten) Namen zu bereinigen und SQL-Einschleusung zu verhindern .

Lassen Sie sich nicht durch mehrere Ebenen von Dollarnotierungen verwirren. Das ist notwendig, um dynamische Abfragen zu erstellen. Ich drücke es so einfach wie möglich aus.