【问题标题】:SQL MAX of multiple columns and retrieve each row多列的 SQL MAX 并检索每一行
【发布时间】:2021-09-15 19:54:53
【问题描述】:

我想获得数据库中近 20 个字段的 MAX 值。我的问题是我还想要一些具有所有这些 MAX 值的其他字段。我正在使用 PostgreSQL。

这是一个例子:

匹配表定义

CREATE TABLE "matches" (
    "id" int4 NOT NULL DEFAULT nextval('match_players_id_seq'::regclass),
    "kills" int4 NOT NULL,
    "deaths" int4 NOT NULL,
    "assists" int4 NOT NULL,
    "gamemode" int4 NOT NULL,
    PRIMARY KEY ("id")
);

匹配表示例数据

id kills deaths assists gamemode
1 0 0 3 1
2 1 0 2 2
3 1 12 0 3
4 7 2 27 1
5 1 4 27 2
6 2 3 1 3
INSERT INTO "matches" ("id", "kills", "deaths", "assists", "gamemode") VALUES
(1, 0, 0, 3, 1),
(2, 1, 0, 2, 2),
(3, 1, 12, 0, 3),
(4, 7, 2, 27, 1),
(5, 1, 4, 27, 2),
(6, 2, 3, 1, 3);

我想要的结果(表格或 JSON 样式)来自上述数据

what amount gamemode id
"kills" 7 1 4
"deaths" 12 3 3
"assists" 27 1 4
{
  "maxKills": {"id": 4, "kills": 7, "gamemode": 1},
  "maxDeaths": {"id": 3, "deaths": 12, "gamemode": 3}
  "maxAssists": {"id": 4, "assists": 27, "gamemode": 1} // Get the first one if 2 are equal
}

这是简化的。这里有一个小pastebin,可以让您了解真正的查询:https://pastebin.com/eT8MNKKe
还有另一个带有@Erwin 答案实现的pastebin:https://pastebin.com/2B8imJTj

两年前我已经发布了这个问题,但我使用的是 NoSQL 数据库 (Mongo):Get objects containing max values for multiple fields using aggregation in mongodb

这是我的想法,不知道是不是最好的:
做2个查询。第一个获取 20 列的 MAX 值,第二个获取包含 20 个聚合 MAX 值的 WHERE 子句的行。我只是不确定当多行具有相同的 MAX 值时该怎么做。

【问题讨论】:

  • 请查看How to Ask。您需要发布您的表定义(不需要完整的定义,只需要 3,4 列您想要最大值)和一些测试数据和 tat 数据的预期结果,全部作为文本 - 没有图像乙>。但我猜你可以使用 max 函数的window 版本。类似max(kills) over (partition by id) 并为每个列名重复。那将只有 1 个查询。
  • 首先,谢谢,我会检查这些链接。我确实放了我的表定义?这是降价而不是图像。我把想要的结果从 JS 更新为 JSON,可能更清楚一点。
  • Mark down 不是表定义,是描述。我无法复制/过去并针对它运行查询。抱歉,我想我应该说张贴表格 ddl。
  • 我明白了!我已经更新了我的问题,我希望这是你的意思。这是我第一次真正导出这样的数据,我不得不删除 40 多个字段,所以我希望它不会被破坏。
  • @ErwinBrandstetter 我没有。我只是在寻求更多建议。我对我的问题所做的修改只是为了按照其他人的要求提供更多背景信息。

标签: sql postgresql greatest-n-per-group union-all


【解决方案1】:

这应该是最快最简单的:

(SELECT 'kills' AS what, kills, gamemode, id   FROM matches ORDER BY kills DESC, id LIMIT 1)
UNION ALL
(SELECT 'deaths'       , deaths, gamemode, id  FROM matches ORDER BY deaths DESC, id LIMIT 1)
UNION ALL
(SELECT 'assists'      , assists, gamemode, id FROM matches ORDER BY assists DESC, id LIMIT 1)
--  more ...

db小提琴here

添加id 作为第二个ORDER BY 表达式。这样,如果多行并列得分最高,则选择id 最小的行。

所有括号都是必需的。见:

如果任何ORDER BY 列可以是NULL,请添加NULLS LAST。见:

【讨论】:

    【解决方案2】:

    您想要获取具有最大值的行。 SQL 结果是由列和行组成的表。这是一种纯 SQL 方法:

    select what, amount, gamemode, id
    from
    (
      select id, gamemode, 'kills' as what, kills as amount, max(kills) over () as max_amount from mytable
      union all
      select id, gamemode, 'deaths' as what, deaths as amount, max(deaths) over () as max_amount from mytable
      union all
      select id, gamemode, 'assists' as what, assists as amount, max(assists) over () as max_amount from mytable
      union all
      ...
    ) all_candidates
    where amount = max_amount;
    

    可能有一些内置的 JSON 函数可以将此结果转换为 JSON。我不知道。也许其他人可以回答这个问题。

    【讨论】:

    • JSON 只是一个示例,因为我不确定如何在文本中显示 SQL 响应。谢谢,我会检查的。如果我有 20 多个字段要 MAX ,那么像这样联合起来仍然“可以”吗?
    • 是的。该任务不是很常见,但如果您想要每列的所有最大行数,那么您可以使用UNION ALL 将它们全部粘合在一起以获得最终数据集。这可能是最简单的方法。
    • 如前所述,SQL 查询结果是一个表。您正在结果中显示匹配表,因此您知道如何在请求中显示表。您应该以同样的方式显示结果表。
    • 是的,我已经根据您的回答更新了我的问题。
    • 再问一个问题。当多行具有相同的最大值时,您将如何处理?现在你的答案都得到了,但我只需要一个。我尝试在您所做的 3 个选择子查询的末尾添加 LIMIT 1,但出现语法错误。谢谢!
    【解决方案3】:

    完美。正如我所怀疑的,您可以使用 max 的窗口版本。唯一真正的困难是设计一些东西来对其进行分区,而不是获得每一行的值。

    select m.*
         , max(m.kills )    over () max_kills
         , max(m.deaths )   over () max_deaths
         , max(m.assists )  over () max_assists
         , max(m.gamemode ) over () max_gamemode  
     from matches m; 
    

    demo。对于演示,我添加了几列只是为了显示“其他列”的包含,但没有填充它们。

    注意:不直接相关,但您应该避免在数据库名称上使用双引号 (")。一旦使用它们必须始终使用。这不值得。

    【讨论】:

    • 您可以删除partition by 子句。如果没有您想要分组的内容,那么只需将括号留空。关于双引号的建议非常好。
    • 谢谢@ThorstenKettner。我知道,只是有时候大脑不会一路走好。 Kalane 我已经更新了对 Thorsten 所说的话的回复。
    • 非常感谢!我认为这个解决方案的问题是,如果我有 2M 行,结果也会给我 2M 行,对吗?如果我在 20 个字段上执行最大值,而不是例如 20 个。顺便说一句,当我进行导出时,TablePlus 会生成引号,但感谢您的建议!
    • 那是正确的。我想我误解了“其他字段”的含义,如果您希望某些它们的最大值只选择那些,或者只在每个字段上使用标准 MAX 函数。
    • 抱歉,我已经用 Thorsten 的想法更新了我的问题。我现在想知道它是否比仅 20 个老式查询要好得多。因为我认为我过度简化了问题:我需要为每个查询进行 2 次连接以获取我需要的列 + 添加多个 where 子句来过滤我正在查看的数据。
    猜你喜欢
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 2022-01-12
    • 1970-01-01
    • 2018-10-15
    相关资源
    最近更新 更多