【问题标题】:Selecting multiple max() values using a single SQL statement使用单个 SQL 语句选择多个 max() 值
【发布时间】:2013-08-31 22:27:16
【问题描述】:

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

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'

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

【问题讨论】:

  • 这和 MySQL 有什么关系?
  • 你提出的初步解决方案一个单一的陈述。您的意思是单个结果row?如果是这样,你有固定数量的 3 种类型,还是有更多,可能是动态的?

标签: sql postgresql pivot crosstab


【解决方案1】:

再一次,对于不仅仅是几个“数据类型”,我建议使用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)

至少 type 是众所周知的:在这种情况下为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 的多层感到困惑。这是构建动态查询所必需的。我说得尽量简单。

【讨论】:

    【解决方案2】:

    如果您想在单独的列中返回每个 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

    【讨论】:

    • 谢谢你成功了!我正在使用 >max(case when data_type='World of Warcraft' then max(value) end) 不起作用,没想到要去掉内部的最大值,非常感谢!
    • @user2146933 很高兴它成功了。你很接近,你不能嵌套这样的聚合函数。 :)
    • 作为一个快速的问题和想法,是否可以根据最近的条目而不是最大条目来执行此操作?
    • @user2146933 您如何确定最新的内容?您有日期时间或 id 值吗?我的建议是,如果您对发布新问题有不同的要求。
    • @bluefeet: .. 这并没有什么问题。更重要的是,因为 OP 并不清楚他到底需要什么。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      相关资源
      最近更新 更多