You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL查询修正:按Edition标记Minecraft唯一最新版本

问题:如何为PostgreSQL中Minecraft版本表的每个Edition标记最新版本

背景

我正在构建一个Minecraft内容查阅Web应用,需要在PostgreSQL的versions表中,为Bedrock('b')和Java('j')两个Edition分别标记对应记录是否为该Edition的最新版本。

现有表结构及初始化数据

CREATE TYPE edition AS ENUM (
    'b',
    'j'
);

CREATE TABLE IF NOT EXISTS versions (
    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
    edition edition NOT NULL,
    major integer NOT NULL,
    minor integer NOT NULL,
    patch integer NOT NULL,
    cycle decimal GENERATED ALWAYS AS (
        CAST(
            (CAST(major AS text) || '.' || CAST(minor AS text)) AS decimal
        )
    ) STORED
);

INSERT INTO versions
    (edition, major, minor, patch)
VALUES
    ('b', 1, 16, 0),
    ('b', 1, 17, 0),
    ('b', 1, 18, 0),
    ('b', 1, 19, 0),
    ('j', 1, 16, 0),
    ('j', 1, 17, 0),
    ('j', 1, 18, 0),
    ('j', 1, 19, 0)
;

错误尝试的查询

我尝试用以下SELECT查询生成is_latest_bedrock和is_latest_java字段,期望每个字段仅出现一次true:

SELECT
    *,
    (
        edition = 'b'
        AND GREATEST(major) = major
        AND GREATEST(minor) = minor
        AND GREATEST(patch) = patch
    ) AS is_latest_bedrock,
    (
        edition = 'j'
        AND GREATEST(major) = major
        AND GREATEST(minor) = minor
        AND GREATEST(patch) = patch
    ) AS is_latest_java
FROM versions
ORDER BY edition, major, minor, patch;

错误结果

实际执行后,同一Edition下的所有记录都被标记为最新版本:

ideditionmajorminorpatchcycleis_latest_bedrockis_latest_java
ddcdc01f-7ac1-4c4a-be7f-5e93902a0855b11601.16truefalse
20d1bf38-75d6-4d96-94fc-fd16d2131319b11701.17truefalse
13252697-4fe6-411f-b151-e4a1ca146e2fb11801.18truefalse
16a1eb78-e566-4649-991c-3ecdd8e6f49bb11901.19truefalse
5ef4657a-c4fc-41f4-b2e1-0aa88e0e4b07j11601.16falsetrue
f68cebf4-a62d-45c5-af67-098f8be041a3j11701.17falsetrue
bd37ff94-5a62-4fc7-a729-6fc353a7c939j11801.18falsetrue
09293db6-aa6b-4cc4-8a58-29afba816d85j11901.19falsetrue

期望结果

每个Edition仅一条最新版本记录被标记为true:

ideditionmajorminorpatchcycleis_latest_bedrockis_latest_java
ddcdc01f-7ac1-4c4a-be7f-5e93902a0855b11601.16falsefalse
20d1bf38-75d6-4d96-94fc-fd16d2131319b11701.17falsefalse
13252697-4fe6-411f-b151-e4a1ca146e2fb11801.18falsefalse
16a1eb78-e566-4649-991c-3ecdd8e6f49bb11901.19truefalse
5ef4657a-c4fc-41f4-b2e1-0aa88e0e4b07j11601.16falsefalse
f68cebf4-a62d-45c5-af67-098f8be041a3j11701.17falsefalse
bd37ff94-5a62-4fc7-a729-6fc353a7c939j11801.18falsefalse
09293db6-aa6b-4cc4-8a58-29afba816d85j11901.19falsetrue

解决方案

问题出在GREATEST()函数的使用上——未指定分组时,它只会返回当前行对应字段的值,导致每一行都满足等于自身的条件。以下两种方法可以实现按Edition标记最新版本:

方法一:使用窗口函数ROW_NUMBER()

SELECT
    v.*,
    (edition = 'b' AND rn = 1) AS is_latest_bedrock,
    (edition = 'j' AND rn = 1) AS is_latest_java
FROM (
    SELECT
        *,
        ROW_NUMBER() OVER (
            PARTITION BY edition
            ORDER BY major DESC, minor DESC, patch DESC
        ) AS rn
    FROM versions
) v
ORDER BY v.edition, v.major, v.minor, v.patch;

通过PARTITION BY edition按版本组分区,ORDER BY major DESC, minor DESC, patch DESC按版本号从高到低排序,每个分区中第一行即为最新版本,标记rn=1,外层再判断是否对应Edition并设置标记字段。

方法二:使用子查询获取每个Edition的最新版本

SELECT
    v.*,
    (v.edition = 'b' AND (v.major, v.minor, v.patch) = (
        SELECT major, minor, patch
        FROM versions
        WHERE edition = 'b'
        ORDER BY major DESC, minor DESC, patch DESC
        LIMIT 1
    )) AS is_latest_bedrock,
    (v.edition = 'j' AND (v.major, v.minor, v.patch) = (
        SELECT major, minor, patch
        FROM versions
        WHERE edition = 'j'
        ORDER BY major DESC, minor DESC, patch DESC
        LIMIT 1
    )) AS is_latest_java
FROM versions v
ORDER BY v.edition, v.major, v.minor, v.patch;

通过子查询分别获取Bedrock和Java的最新版本号组合,再与主表每条记录对比,匹配成功的标记为true。

两种方法均可满足需求,窗口函数的性能更优,适合数据量较大的场景。


内容的提问来源于stack exchange,提问作者ravinggenius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 17:01:07