使用单个SQL语句选择多个max()值

use*_*933 2 sql postgresql pivot crosstab

我有一个表,其数据看起来像这样:

data_type, value
World of Warcraft, 500
Quake 3, 1500
Quake 3, 1400
World of Warcraft, 1200
Final Fantasy, 100
Final Fantasy, 500
Run Code Online (Sandbox Code Playgroud)

我想要做的是在一个语句中选择每个值的最大值.我知道我可以轻松做点什么

select data_type, max(value)
from table
where data_type = [insert each data type here for separate queries]
group by data_type
Run Code Online (Sandbox Code Playgroud)

但我希望它显示的是

select data_type, 
  max(value) as 'World of Warcraft', 
  max(value) as 'Quake 3', 
  max(value) as 'Final Fantasy'
Run Code Online (Sandbox Code Playgroud)

所以我在一个语句中得到每个的最大值.我该怎么做呢?

Erw*_*ter 6

再一次,对于不止一些"数据类型",我建议使用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)
Run Code Online (Sandbox Code Playgroud)

返回:

type | Final Fantasy | Quake 3 | World of Warcraft
-----+---------------+---------+-------------------
max  | 500           | 1500    |    1200
Run Code Online (Sandbox Code Playgroud)

更多基础知识解释:
PostgreSQL交叉表查询

动态解决方案

棘手的是让它完全变得动态:让它发挥作用

  • 一个未知数量的列(在这种情况下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
Run Code Online (Sandbox Code Playgroud)

这会生成您实际需要的查询.在同一事务中运行第二个以避免并发问题.

请注意策略性使用quote_literal()quote_ident()清理各种非法(列)名称并防止SQL注入.

不要被多层美元引用混淆.这对于构建动态查询是必要的.我说它尽可能简单.