再一次,对于不仅仅是几个“数据类型”,我建议使用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)
回报:
type | Final Fantasy | Quake 3 | World of Warcraft
-----+---------------+---------+-------------------
max | 500 | 1500 | 1200
更多基础知识说明:
PostgreSQL Crosstab Query
动态解决方案
棘手的事情是让它完全动态化:让它为
- 未知数量的列(在这种情况下为 data_types)
- 名称未知(再次为 data_types)
至少类型是众所周知的:integer
在这种情况下。
简而言之:这在当前的 PostgreSQL(包括 9.3)中是不可能的。存在与多态类型的近似值以及规避数组或 hstore 类型限制的方法。可能对你来说已经足够好了。但严格不可能在单个 SQL 查询中获得单个列的结果。SQL 对类型非常严格,并且想知道期望返回什么。
但是,它可以通过两个查询来完成。第一个构建要使用的实际查询。基于上述简单案例:
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
这会生成您实际需要的查询。在同一事务中运行第二个以避免并发问题。
注意战略性地使用quote_literal()
和quote_ident()
清理各种非法(对于列)名称并防止SQL 注入。
不要被多层美元报价所迷惑。这是构建动态查询所必需的。我说得尽可能简单。