Endnu en gang, for mere end blot nogle få "datatyper", foreslår jeg at bruge 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)
Returnerer:
type | Final Fantasy | Quake 3 | World of Warcraft
-----+---------------+---------+-------------------
max | 500 | 1500 | 1200
Mere forklaring på det grundlæggende:
PostgreSQL Crosstab Query
Dynamisk løsning
Det vanskelige er at gøre dette helt dynamisk :for at få det til at fungere for
- et ukendt nummer af kolonner (data_typer i dette tilfælde)
- med ukendte navne (data_types igen)
I det mindste typen er velkendt:integer
i dette tilfælde.
Kort sagt:det er ikke muligt med nuværende PostgreSQL (inklusive 9.3). Der er tilnærmelser med polymorfe typer og måder at omgå begrænsningerne med arrays eller hstore-typer. Kan være god nok for dig. Men det er strengt ikke muligt for at få resultatet med individuelle kolonner i en enkelt SQL-forespørgsel. SQL er meget rigid med hensyn til typer og vil gerne vide, hvad de kan forvente tilbage.
Men , kan det gøres med to forespørgsler. Den første bygger selve forespørgslen til brug. Bygger på ovenstående simple case:
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
Dette genererer den forespørgsel, du faktisk har brug for. Kør den anden i samme transaktion for at undgå problemer med samtidighed.
Bemærk den strategiske brug af quote_literal()
og quote_ident()
at rense alle former for ulovlige (til kolonner) navne og forhindre SQL-injektion .
Bliv ikke forvirret af flere lag af dollarnotering. Det er nødvendigt for at bygge dynamiske forespørgsler. Jeg siger det så enkelt som muligt.