【问题标题】:MIN function in SQL not working as expectedSQL 中的 MIN 函数未按预期工作
【发布时间】:2021-04-30 10:39:18
【问题描述】:

我有一张表格,其中列出了游戏玩家以及他们在游戏中的等级变化历史(初级、中级、高级、精英、专业)。我正在尝试构建一个查询,以准确识别 2021 年迄今为止首次达到高级或更高级别的人(玩家有可能跳过排名,所以我想要他们达到高级或高级的最早日期、精英或专业级别)。我目前正在使用这个查询:

SELECT *
FROM (
SELECT p."ID", ra."NewRank", MIN(ra."EffectiveDate") AS "first_time_adv"
FROM rankachievement ra
JOIN player p
ON ra."ID" = p."ID"
WHERE ra."NewRank" IN ('Advanced',
        'Elite',
        'Pro')
GROUP BY 1, 2) AS t
WHERE t."first_time_adv" > '1/1/2021'
ORDER BY 1 

现在,这是在拉动所有2021年第一次达到高级水平的人,但它也在拉动一些以前在2020年达到高级水平的人,现在已经达到了更高的水平——我不想包括这些人,这就是为什么我在日期中使用了 MIN。

例如,它正确地拉入了在 1 月 2 日达到高级的玩家 1 和 2,以及在跳过高级后于 1 月 4 日达到精英的玩家 4(从中级直接进入精英)。但它也吸引了玩家 3,他们在 2020 年 12 月 30 日达到高级,然后在 1 月 10 日达到精英 - 我不希望玩家 3 被包括在内,因为他们在 2021 年之前第一次达到高级。我怎样才能得到我的查询排除这样的人?

【问题讨论】:

    标签: postgresql subquery min


    【解决方案1】:

    您将获得玩家 3 的两个结果...一个是高级玩家,另一个是精英玩家,因为您按 NewRank 分组。玩家 3 达到高级的那个会从你的WHERE t.first_time_adv > '1/1/2021' 的结果集中删除,精英通过。我建议尝试将FILTEROVERMIN() 一起使用。

    内部查询的结果包括以下内容:

    id | new_rank | MIN(EffectiveDate)
    ---+----------+-------------------
    1  | advanced | the min date for this record (12/30/2020)
    1  | elite    | the min date for this record (01/10/2021)
    

    这是因为您在对 IDNewRank 进行分组时获得了 MIN。您希望MIN 覆盖该玩家的所有记录。如果您仅按 ID 分组,您可能会得到您正在寻找的行为,但这需要您从 SELECT 子句中删除 NewRank


    我怀疑您希望在最终结果集中获得排名,因此请尝试以下操作:

    WITH data AS
    (
    SELECT p."ID"
         , ra."NewRank"
         , ra."EffectiveDate"
         , MIN(ra."EffectiveDate")
           FILTER (WHERE ra."NewRank" = 'Advanced')
           OVER (PARTITION BY p."ID") AS "first_time_adv"
      FROM rankachievement ra
      JOIN player p ON ra."ID" = p."ID"
     WHERE ra."NewRank" IN ('Advanced', 'Elite', 'Pro')
    )
    SELECT *
      FROM data d
     WHERE d."first_time_adv" > '1/1/2021'
    ORDER BY 1
    ;
    

    以前您可以找到任何rank IN ('Advanced', 'Elite', 'Pro')MIN(EffectiveDate)...现在您真正找到了当玩家到达'Advanced' 时的EffectiveDate

    【讨论】:

    • @J Spratt 再问你一个问题。如果我尝试从 select 子句中删除 NewRank 列并按 ID 分组,以便我只为每个玩家获得一行,我会收到一个错误,即生效日期必须出现在 group by 子句中或在聚合函数中使用 - 但是它在聚合函数 MIN 中使用。由于我正在使用 FILTER 和 OVER,我需要做一些特别的调整来进行此调整吗?
    • 我在示例中的SELECT 子句中添加了一个额外的字段。如果你不需要它,你可以删除它。由于您使用的是窗口函数OVER,因此您不需要使用GROUP BY 子句,因为窗口函数应用于整个结果集。分组由窗口函数中的PARTITION BY 处理。当使用没有OVER 的聚合函数时,您需要按SELECT 子句中的所有其他内容进行分组。我希望这能回答你的问题。
    猜你喜欢
    • 2013-07-26
    • 2018-02-01
    • 1970-01-01
    • 2020-10-08
    • 2019-10-30
    • 2015-04-11
    • 2022-01-25
    • 2019-12-22
    • 1970-01-01
    相关资源
    最近更新 更多