【问题标题】:How to use LIMIT and OFFSET when joining one to many tables with postgresql?使用 postgresql 连接一对多表时如何使用 LIMIT 和 OFFSET?
【发布时间】:2021-01-17 16:17:57
【问题描述】:

我正在使用带有 postgres 数据库的 sqlalchemy 核心,并且正在实现 JSON:API spec

对于分页,我只使用基本的LIMITOFFSET。因此,例如以下两个表:

session
id
name

appearance
id
date
session_id

对于会话,我可以简单地对其进行分页:

SELECT id, name FROM session LIMIT 20 OFFSET 40

由于数据保存时间的限制,我们的数据库只能增长到如此之大,所以我不担心LIMIT OFFSET 方法可能造成的减速。在上面的示例中,它工作正常,记录数始终等于限制,或者如果在最后,则更少。但是当我有以下问题时,我的问题就来了:

SELECT s.id, s.name, a.date FROM session s JOIN appearance a on s.id = a.session_id LIMIT 3 OFFSET 0

因为可能有两个 appearance 行引用会话,所以我最终可能会得到类似的结果:

s.id     s.name                 a.date
1        FirstSesh              24/04/14
1        FirstSesh              01/01/20
2        Hello                  09/09/10

现在我只返回了一行,可能还有另一行,或者只是另一行的一部分。

我想到的第一个解决方案是:

SELECT s.id, s.name, a.date FROM (SELECT id, name FROM session LIMIT 3 OFFSET 0) s JOIN appearance a on s.id = a.session_id

但现在这会限制在 s 上使用 WHEREORDER 的能力,因为它将被限制为三个。而且我不能只将所有这些条件放在子查询中,因为我建立 JSON:API 的关系部分的方式,并且因为我想限制我是否返回 session 也基于如果例如Appearances.date 在 2012 年之前。这会导致同样的问题。

作为参考,我的 JSON:API 设置中的每种类型都有自己的查询,然后在用于关系时,这些查询用作子查询,这允许简单的递归关系和新关系的简单实现。

如果我可以根据会话 id 的组来执行类似使用 LIMITOFFSET 的操作,那么我认为这可能有效吗?但我不确定我会怎么做?

【问题讨论】:

    标签: sql postgresql sql-order-by window-functions sql-limit


    【解决方案1】:

    您可以使用窗口函数。例如,这会为您提供前 3 个会话(按 id 排序),以及所有相应的外观(无论有多少匹配)。

    SELECT s.id, s.name, a.date 
    FROM (SELECT s.*, ROW_NUMBER() OVER(ORDER BY id) rn FROM sessions) s 
    INNER JOIN appearance a ON s.id = a.session_id 
    WHERE s.rn BETWEEN 0 AND 3
    ORDER BY s.rn, a.date
    

    然后,您可以通过更改 BETWEEN 条件的边界来“分页”结果集。

    编辑

    或者:

    SELECT id, name, date
    FROM (
        SELECT s.id, s.name, a.date,
            DENSE_RANK () OVER(ORDER BY id) rn
        FROM sessions s 
        INNER JOIN appearance a ON s.id = a.session_id 
        WHERE a.is_admin = 1
    ) c
    WHERE s.rn BETWEEN 0 AND 3
    ORDER BY rn, date
    

    【讨论】:

    • 这个有同样的问题吗?例如。让我们假设外观有另一个字段,is_admin。如果我添加到那个查询WHERE is_admin is True,那么它只适用于三个已经选择的会话。因此,如果前三个会话没有出现 is_admin 为 True 的外观,或者例如第三、第四、第五和第六个会话出现 is_admin 时,我最终不会得到任何结果,在您的版本中我只得到第一排,第三排。而不是获得第三、第四和第五。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-07
    • 2017-12-25
    • 1970-01-01
    • 2021-05-26
    • 2012-08-25
    • 2013-04-13
    • 1970-01-01
    相关资源
    最近更新 更多