【问题标题】:Find lagging rows of a query omitted by a WHERE clause in SQL/SQLite查找 SQL/SQLite 中 WHERE 子句省略的查询的滞后行
【发布时间】:2022-01-12 04:12:57
【问题描述】:

设置

我有一张比赛时间表,列出了跑步者、他们的团队和他们的比赛时间:

CREATE TABLE race (person TEXT, team TEXT, timer FLOAT);

INSERT INTO race
  (person, team, timer)
VALUES
  ("ahmed", "red", 4.3),
  ("baadur", "green", 4.4),
  ("carel", "red", 4.5),
  ("dada", "green", 4.9),
  ("eder", "green", 5.0),
  ("farai", "red", 5.1);

我可以列出红色团队中的所有人及其排名:

SELECT person, ROW_NUMBER() OVER(ORDER BY timer) AS ranking FROM race WHERE team="red";

会发光

person ranking
ahmed 1
carel 2
farai 3

问题

我还想获得跟随这些红色跑步者中的每一个的跑步者的名字,即,谁的时间第二慢——所以我想要:

person ranking next runner
ahmed 1 baadur
carel 2 dada
farai 3 null

请注意,由于没有人比 Farai 的时间慢,Farai 的第三列是空的。

我可以通过单个查询有效地做到这一点吗?

注意事项

我想避免首先通过一个查询获取红色跑步者的列表及其时间,然后再进行另外三个(或更一般地N)查询以获取下一次跑步者,例如,这就是我确实想做:

SELECT person FROM race WHERE timer>=4.3 AND person != "ahmed" LIMIT 1;
SELECT person FROM race WHERE timer>=4.5 AND person != "carel" LIMIT 1;
SELECT person FROM race WHERE timer>=5.1 AND person != "farai" LIMIT 1;
-- ????

我也许可以将上述方法重新设计为单个查询而不是多个单独的查询,但我觉得如果有办法为每个查询运行子查询,应该可以在单个查询中得到我想要的与WHERE team="red" 子句匹配的行以查找下一行(可以通过timer 上的索引来快速查找),但我不确定这是否可能。

例如,我可以使用 SQLite 的lag 窗口函数来实现吗? lag 本身会查看符合我的 WHERE team="red" 标准的行,因此如果他们在绿队或其他非红队,它不会返回下一个最慢的跑步者。

这种查询有通用术语吗?

可能有许多团队和许多跑步者,所以我想知道如何使这种查找尽可能高效。

【问题讨论】:

    标签: sql sqlite


    【解决方案1】:

    在此处使用LAG,以及带有分区的ROW_NUMBER

    WITH cte AS (
        SELECT *, ROW_NUMBER() OVER (PARTITION BY team ORDER BY timer) ranking,
                  LEAD(person) OVER (ORDER BY timer) next_runner
        FROM race
    )
    
    SELECT person, ranking, next_runner
    FROM cte
    WHERE team = 'red'
    ORDER BY ranking;
    

    Demo

    【讨论】:

    • 谢谢蒂姆!分区 ROW_NUMBER 是否意味着 SQLite 必须对整个表进行分区?也就是说,如果有很多团队和很多行,这会有效吗? ROW_NUMBER 是否足够聪明,只能查看我在 WHERE team = "red" 子句中指定的团队?对不起,如果我问的是一个不好的问题,甚至是一个无效的问题。
    • 是的,在我上面的回答中,ROW_NUMBER 被应用于整个表,并按团队进行分区。这意味着每个团队的记录组都有自己的行号。我这样做是因为 LEAD 如您所愿,它需要应用于整个表格。我们限制在外部查询中只有红色跑步者。
    • 好的,明白了,数据库引擎需要枚举完整分区和所有团队,甚至是我不感兴趣的团队,这是有道理的,因为LEAD 可能来自其中之一那些其他球队。出于性能原因,听起来最好添加另一列“next_runner”,当我在此表中插入每一行时,我会显式填充它,并预先计算它而不是这个非常酷的查询?
    • @AhmedFasih 您的上述评论在其解释中是正确的。计算列的问题是,如果您的基础数据将来可能会发生变化,例如由于更正?然后,您还必须更新 next_runner 计算列。由于像这样的边缘情况,我更喜欢动态计算领先优势,以避免额外的工作。
    • 完美,明白!非常感谢?!这是一个可爱的查询,我会详细研究它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2015-09-12
    • 1970-01-01
    • 2021-04-07
    • 2012-01-23
    • 1970-01-01
    • 2015-02-07
    相关资源
    最近更新 更多