Återigen, för mer än bara några "datatyper", föreslår jag att du använder 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)
Returnerar:
type | Final Fantasy | Quake 3 | World of Warcraft
-----+---------------+---------+-------------------
max | 500 | 1500 | 1200
Mer förklaring till grunderna:
PostgreSQL Crosstab Query
Dynamisk lösning
Det knepiga är att göra detta helt dynamiskt :för att få det att fungera för
- ett okänt nummer av kolumner (data_typer i det här fallet)
- med okända namn (data_types igen)
Åtminstone typen är välkänt:integer
i det här fallet.
Kort sagt:det är inte möjligt med nuvarande PostgreSQL (inklusive 9.3). Det finns approximationer med polymorfa typer och sätt att kringgå begränsningarna med arrayer eller hstore-typer. Kan vara tillräckligt bra för dig. Men det är strängt taget inte möjligt för att få resultatet med enskilda kolumner i en enda SQL-fråga. SQL är väldigt rigid när det gäller typer och vill veta vad man kan förvänta sig tillbaka.
Men , det kan göras med två frågor. Den första bygger den faktiska frågan som ska användas. Bygger på ovanstående enkla 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
Detta genererar den fråga du faktiskt behöver. Kör den andra i samma transaktion för att undvika samtidighetsproblem.
Notera den strategiska användningen av quote_literal()
och quote_ident()
att sanera alla typer av olagliga (för kolumner) namn och förhindra SQL-injektion .
Bli inte förvirrad av flera lager av dollarnotering. Det är nödvändigt för att bygga dynamiska frågor. Jag uttryckte det så enkelt som möjligt.