2

我有一个表,其中的数据如下所示:

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'

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

4

3 回答 3

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)中是不可能的。存在与多态类型的近似值以及规避数组或 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 注入

不要被多层美元报价所迷惑。这是构建动态查询所必需的。我说得尽可能简单。

于 2013-08-28T22:44:41.710 回答
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

于 2013-08-28T17:52:01.883 回答
1

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

select
    data_type,
    max(value) as value
from table1
group by data_type
于 2013-08-28T18:02:50.750 回答