首页 文章

选择直到postgresql中的行匹配?

提问于
浏览
1

有没有办法在满足某些条件之前选择行?即一种 limit ,但不限于 N 行,但直到第一个非匹配行的所有行?

例如,假设我有 table :

CREATE TABLE t (id SERIAL PRIMARY KEY, rank INTEGER, value INTEGER);
INSERT INTO t (rank, value) VALUES  ( 1, 1), (2, 1), (2,2),(3,1);

那是:

test=# SELECT * FROM t;
 id | rank | value
----+------+-------
  1 |    1 |     1
  2 |    2 |     1
  3 |    2 |     2
  4 |    3 |     1
(4 rows)

我想按等级排序,并选择直到第一行超过1 .

SELECT * FROM t ORDER BY rank UNTIL value>1

我想要前两行回来?

一种解决方案是使用子查询和 bool_or

SELECT * FROM
( SELECT id, rank, value, bool_and(value<2) OVER (order by rank, id) AS ok FROM t ORDER BY rank) t2
WHERE ok=true

但是,即使我只想要一小撮,也不会最终通过所有行?

(真实世界的背景:我在表中有时间戳事件,我可以使用窗口查询超前/滞后来选择两个事件之间的时间,我希望 now 中的所有事件都返回,只要它们发生的间隔不到10分钟 - lead/lag 窗口查询使事情变得复杂,所以这里的简化示例)

编辑:按 rank, id 制作窗口功能顺序

3 回答

  • 1

    这可能并不比你的解决方案好,因为你提出了一个问题,“这最终会不是通过所有行?”

    我可以告诉你 - 解释计划与你的解决方案不同 . 我不知道PostgreSQL的内容是如何工作的,但如果我正在写一个“max”函数,我会认为它总是O(n) . 相比之下,您的订单是平均情况O(n log n),最差情况是O(n ^ 2) .

    也就是说,我不能否认这会经历所有行:

    select * from sandbox.t
    where id < (select min (id) from sandbox.t where value > 1)
    

    但有一点需要澄清的是,除非您扫描所有行,否则我不确定如何确定最小值 . 每次在所有记录中调用聚合概念时,这是否意味着您必须读取所有行?

  • 1

    你想要的是一种停止条件 . 据我所知,SQL中没有这样的东西,至少是PostgreSQL的方言 .

    您可以做的是使用PL / PgSQL过程从游标中读取行并返回它们直到满足停止条件 . 它赢了't be super fast, but it'好吧 . 对于带有 IF expression THEN exit; ELSE return next; END IF; 的查询,它只是一个 FOR 循环 . 不需要显式游标,因为如果你 FOR 循环查询,PL / PgSQL将在内部使用一个游标 .

    另一种选择是在应用程序中创建一个游标并从中读取行块,然后在满足停止条件时丢弃最后一个块的一部分 .

    无论哪种方式,光标都将是您想要的 .


    顺便说一下,停止表达式实际上并不太难以在PostgreSQL中实现 . 您必须实现新的执行程序节点类型,但新的CustomScan支持将使扩展中的实际操作成为可能 . 然后你只需要评估一个表达式来决定是否继续获取行 .

  • 0

    您可以尝试以下内容:

    select * from t, (
      select rank from t where value = 1 order by "rank" limit 1) x
    where t.rank <= x.rank order by rank;
    

    它将通过表的第一部分进行两次传递(您可以通过在(rank,value = 1)上创建索引来切割)但如果您有一个排名索引,则不应评估表的其余部分 .

    [如果你可以在where子句中使用窗口表达式,你可以使用窗口表达式来确保任何先前的行没有value = 1 ..但即使这是可能的,那么让查询求值程序用来限制搜索将是另一个挑战 . ]

相关问题