SQL 多列的 MAX 并检索每一行

SQL MAX of multiple columns and retrieve each row

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

这是一个例子:

匹配Table定义

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")
);

匹配table示例数据

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);

我想要的结果(Table或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):

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

您想获取具有最大值的行。 SQL 结果是由列和行组成的 table。这是一种纯粹的 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。我不知道。也许其他人可以回答这个问题。

完美。我怀疑您可以使用 window 版本的 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。对于演示,我添加了几列只是为了显示 'other columns' 的包含,但没有填充它们。

注意:没有直接关系,但您应该避免在数据库名称上使用双引号 (")。一旦使用,它们 必须始终 使用。只是不值得付出努力。

这应该是最快最简单的:

(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<>fiddle here

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

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

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

  • Sort by column ASC, but NULL values first?