sql >> Database >  >> RDS >> PostgreSQL

Meerdere max()-waarden selecteren met een enkele SQL-instructie

Nogmaals, voor meer dan alleen een paar "gegevenstypen", raad ik aan om crosstab() te gebruiken :

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)

Retourneren:

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

Meer uitleg voor de basis:
PostgreSQL Crosstab Query

Dynamische oplossing

Het lastige is om dit volledig dynamisch te maken :om het te laten werken voor

  • een onbekend nummer van kolommen (data_types in dit geval)
  • met onbekende namen (nogmaals data_types)

Tenminste het type is bekend:integer in dit geval.

Kortom:dat kan niet met het huidige PostgreSQL (inclusief 9.3). Er zijn benaderingen met polymorfe typen en manieren om de beperkingen met arrays of hstore-typen te omzeilen. Misschien goed genoeg voor je. Maar het is strikt niet mogelijk om het resultaat met afzonderlijke kolommen in een enkele SQL-query te krijgen. SQL is erg rigide over typen en wil weten wat ze terug kunnen verwachten.

Echter , het kan met twee vragen. De eerste bouwt de eigenlijke query die moet worden gebruikt. Voortbouwend op het bovenstaande eenvoudige geval:

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

Dit genereert de query die u daadwerkelijk nodig heeft. Voer de tweede uit binnen de dezelfde transactie om gelijktijdigheidsproblemen te voorkomen.

Let op het strategische gebruik van quote_literal() en quote_ident() om allerlei illegale (voor kolommen) namen te zuiveren en SQL-injectie te voorkomen .

Raak niet in de war door meerdere lagen dollarcitaten. Dat is nodig voor het bouwen van dynamische queries. Ik heb het zo eenvoudig mogelijk gesteld.



  1. PostgreSQL-prestaties benchmarken

  2. ExecuteScalar vs ExecuteNonQuery bij het retourneren van een identiteitswaarde

  3. Geldige datumcontroles in Oracle

  4. foreach %dopar% + RPostgreSQL