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

时间:2013-08-28 17:48:40

标签: 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

我想要做的是在一个语句中选择每个值的最大值。我知道我可以很容易地做一些像

这样的事情
select data_type, max(value)
from table
where data_type = [insert each data type here for separate queries]
group by data_type

但我希望它显示的是

select data_type, 
  max(value) as 'World of Warcraft', 
  max(value) as 'Quake 3', 
  max(value) as 'Final Fantasy'

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

3 个答案:

答案 0 :(得分: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)

返回:

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

基础知识的更多解释:
PostgreSQL Crosstab Query

动态解决方案

棘手的是让完全动态:使其适用于

  • 未知数量列(本例中为data_types)
  • 未知名称(再次使用data_types)

至少类型众所周知:在这种情况下为integer

简而言之:使用当前的PostgreSQL(包括9.3)是不可能的。有approximations with polymorphic types and ways to circumvent the restrictions with arrays or hstore types。对你来说可能够好。但是在单个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() and quote_ident()的战略用途,以清理各种非法(列名)名称并阻止 SQL注入

不要被多个dollar-quoting层混淆。这对于构建动态查询是必要的。我说它尽可能简单。

答案 1 :(得分:4)

如果要在单独的列中返回每个data_type的最大值,那么您应该能够使用带有CASE表达式的聚合函数:

select
  max(case when data_type='World of Warcraft' then value end) WorldofWarcraft,
  max(case when data_type='Quake 3' then value end) Quake3,
  max(case when data_type='Final Fantasy' then value end) FinalFantasy
from yourtable;

请参阅SQL Fiddle with Demo

答案 2 :(得分:1)

如果您希望将数据聚合在单个字符串中,请使用bluefeet示例,如果您需要一个记录集,其中包含每种类型的记录:

select
    data_type,
    max(value) as value
from table1
group by data_type