【问题标题】:Postgres query selection logicPostgres 查询选择逻辑
【发布时间】:2022-11-24 12:14:14
【问题描述】:
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)
;

我正在构建一个 Web 应用程序来引用 Minecraft 的各个方面。我正在尝试在我的 versions 表中构建一个存储的生成列,以指定相关记录是否指定每个版本的最高版本号。 (Minecraft 作为两个独立且不兼容的版本发布:Bedrock (b) 和 Java (j)。)

鉴于上面的结构和数据,我希望以下选择对每个 is_latest_* 字段仅返回一次 true,对所有其他字段返回 false

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;

相反,我看到的是每条记录都被标记为每个版本的最高版本:

id edition major minor patch cycle is_latest_bedrock is_latest_java
ddcdc01f-7ac1-4c4a-be7f-5e93902a0855 b 1 16 0 1.16 true false
20d1bf38-75d6-4d96-94fc-fd16d2131319 b 1 17 0 1.17 true false
13252697-4fe6-411f-b151-e4a1ca146e2f b 1 18 0 1.18 true false
16a1eb78-e566-4649-991c-3ecdd8e6f49b b 1 19 0 1.19 true false
5ef4657a-c4fc-41f4-b2e1-0aa88e0e4b07 j 1 16 0 1.16 false true
f68cebf4-a62d-45c5-af67-098f8be041a3 j 1 17 0 1.17 false true
bd37ff94-5a62-4fc7-a729-6fc353a7c939 j 1 18 0 1.18 false true
09293db6-aa6b-4cc4-8a58-29afba816d85 j 1 19 0 1.19 false true

这是我期望/想要看到的结果集:

id edition major minor patch cycle is_latest_bedrock is_latest_java
ddcdc01f-7ac1-4c4a-be7f-5e93902a0855 b 1 16 0 1.16 false false
20d1bf38-75d6-4d96-94fc-fd16d2131319 b 1 17 0 1.17 false false
13252697-4fe6-411f-b151-e4a1ca146e2f b 1 18 0 1.18 false false
16a1eb78-e566-4649-991c-3ecdd8e6f49b b 1 19 0 1.19 true false
5ef4657a-c4fc-41f4-b2e1-0aa88e0e4b07 j 1 16 0 1.16 false false
f68cebf4-a62d-45c5-af67-098f8be041a3 j 1 17 0 1.17 false false
bd37ff94-5a62-4fc7-a729-6fc353a7c939 j 1 18 0 1.18 false false
09293db6-aa6b-4cc4-8a58-29afba816d85 j 1 19 0 1.19 false true

如何更新查询以仅将一个 Bedrock 版本和一个 Java 版本标记为最新?

【问题讨论】:

  • 当您的数据包含自然复合键时,为什么要使用 UUID 作为 PK?
  • 使用 MAX() 而不是 GREATEST。因此 MAX() 通常用于返回数据库中列中的最大值。该表可能包含许多行,但此函数返回具有最大值的行。另一方面,GREATEST() 从传递给它的参数列表中返回最大值参数。所以你可以给这个函数传递 3 个参数,它会返回具有最大值的那个。

标签: sql postgresql


【解决方案1】:

ROW_NUMBER 窗口函数,并在 edition 类型上进行分区对于这种情况可能是一个很好的解决方案 - 您仍然希望返回所有记录。

请参阅下面的查询,它在 edition 类型上显示窗口并为每个记录分配一个行号,按 majorminorpatch 降序排列。为了为最新结果生成一个布尔值,= 1 仅用于断言此记录是否是窗口排序中的第一条。这条路线的优点是它会输出一个指标任何edition输入将来可能添加的表格。

询问:

SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY edition ORDER BY major desc, minor desc, patch desc) = 1 as is_latest_version_for_edition
FROM versions
ORDER BY edition, major, minor, patch;

结果:

id edition major minor patch cycle is_latest_version_for_edition
6ef44cf8-10d6-4cb9-874a-ff9322ce708b b 1 16 0 1.16 false
9d5fc712-819f-4d9d-ada7-fa5371ae1a7e b 1 17 0 1.17 false
046c76f2-c8be-4686-ab0d-1387fd798579 b 1 18 0 1.18 false
3ba9b494-acf4-4eda-ae46-b305abebf93d b 1 19 0 1.19 true
87c2552b-3591-416a-baa1-6297b3b0e6c2 j 1 16 0 1.16 false
51872b9b-ec3f-45d3-8be7-532946b699a8 j 1 17 0 1.17 false
2205b1df-4d7b-4eee-ac17-c153f2374339 j 1 18 0 1.18 false
f65635e4-e687-4a30-a69d-9154b6d61dd6 j 1 19 0 1.19 true

DbFiddle:https://www.db-fiddle.com/f/sB7zE1syp8xNmnEk2oizCR/0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    相关资源
    最近更新 更多