【问题标题】:Limit and offset a search query that has a left join限制和偏移具有左连接的搜索查询
【发布时间】:2019-06-05 17:19:58
【问题描述】:

我有两个表:任务和页面。第一页有一个列多次引用第二个表,称为 page_number。我想获取第一个表的所有字段以及相同 tasks.id 的所有 页码 值。我获取这些数据的查询是这样的:

SELECT
TASKS.ID,TASKS.URL,TASKS.ASSIGNEE,PAGES.TASK_ID,PAGES.PAGE_NUMBER
FROM TASKS
INNER JOIN (SELECT * FROM TASKS ORDER BY TASKS.ID LIMIT ? OFFSET ?)
AS T ON (TASKS.ID=T.ID)
LEFT JOIN PAGES ON (TASKS.ID=PAGES.TASK_ID);

这行得通,我得到这样的输出:

      id  |          url          | assignee | task_id | page_number
------+-----------------------+----------+---------+-------------
   15 | /vector.pdf           |          |      15 |           1
   15 | /vector.pdf           |          |      15 |           2
   23 | /raster.pdf           |          |      23 |           1
   23 | /raster.pdf           |          |      23 |           2
   23 | /raster.pdf           |          |      23 |           4
 1001 | https://everette.com  |          |    1001 |           1
 1001 | https://everette.com  |          |    1001 |           2
 1002 | https://scarlett.com  |          |    1002 |           1
 1002 | https://scarlett.com  |          |    1002 |           2
 1002 | https://scarlett.com  |          |    1002 |           3
 1002 | https://scarlett.com  |          |    1002 |           4
 1002 | https://scarlett.com  |          |    1002 |           5
 1002 | https://scarlett.com  |          |    1002 |           6
 1002 | https://scarlett.com  |          |    1002 |           7

但我遇到了其他要求:我还需要在同一个查询中获取 TASKS 表的总数(用于前端的分页),并且我需要能够搜索结果表(即查找表中的任何子字符串)。 为了搜索表格,我这样做了:

SELECT 
TASKS.ID,TASKS.URL,TASKS.ASSIGNEE,PAGES.TASK_ID,PAGES.PAGE_NUMBER
FROM TASKS
INNER JOIN (SELECT * FROM TASKS ORDER BY TASKS.ID LIMIT ? OFFSET ?)
AS T ON (TASKS.ID=T.ID)
LEFT JOIN PAGES ON (TASKS.ID=PAGES.TASK_ID)
WHERE TASKS.URL  LIKE ?
OR CAST(TASKS.ID AS TEXT) LIKE ?

我确实得到了结果,但是 LIMIT 和 OFFSET 在 WHERE 子句之前对连接表起作用,因此我将 LIMIT 设置为 10 并将 OFFSET 设置为 5,尝试查找前 5 条记录中的记录并没有结果,因为匹配的记录在原始表中更进一步:

SELECT
TASKS.ID,TASKS.URL,TASKS.ASSIGNEE,PAGES.TASK_ID,PAGES.PAGE_NUMBER
FROM TASKS
INNER JOIN (SELECT * FROM TASKS ORDER BY TASKS.ID LIMIT 10 OFFSET 5)
AS T ON (TASKS.ID=T.ID)
LEFT JOIN PAGES ON (TASKS.ID=PAGES.TASK_ID)
WHERE TASKS.URL  LIKE '%everette%'
OR CAST(TASKS.ID AS TEXT) LIKE 99

实际输出:

 id | url | assignee | task_id | page_number
----+-----+----------+---------+-------------
(0 rows)

预期输出:

id  |          url          | assignee | task_id | page_number
------+-----------------------+----------+---------+-------------
1001 | https://everette.com  |          |    1001 |           1
1001 | https://everette.com  |          |    1001 |           2

我应该如何构造这个查询,以便获得与 WHERE 子句匹配的所有记录,最多获得 limit 个任务?

顺便说一句,我正在使用 PostgreSQL。提前感谢您的帮助。

【问题讨论】:

  • 嗨。这还不清楚。 “搜索表”和“最后使用 WHERE 子句过滤”到底是什么意思?此外,还不清楚您所指的“结果表”(某些子选择?某些 FROM 子句的结果?)和“过滤结果”。请阅读minimal reproducible example 并采取行动。包括你可以做的部分的代码。
  • 抱歉,为了清楚起见,我现在添加了完整的 SQL 查询以及实际和所需的输出。
  • 这样更好。但是 MCVE 包含我们可以剪切、粘贴和运行的代码,包括 DDL 和(小)输入。另外:你还不清楚。什么表是“WHERE 子句之前的连接表”,“LIMIT 和 OFFSET 起作用”是什么意思?请清楚地识别特定的子表达式。您的段落以“我确实得到了结果,但是”开头也没有意义。例如,什么是“试图寻找”?再次,讨论清楚识别的子表达式的值。 (并且最好通过提供适用于零件的代码来演示。)并且“搜索结果表”仍然没有任何意义。等等。
  • PS 您没有根据输入中出现的行清楚地描述输出中应该出现的行。 PS如果你想限制匹配个任务,为什么要限制一个不匹配个任务表呢? PS 如果您希望 DBMS 从给定的子表达式值重复返回页面,那么您需要在每次请求新页面时重新计算该值。

标签: sql postgresql left-join limit offset


【解决方案1】:

您可以将该计数添加到列列表中:

SELECT ... column list ..., 
       (select count(*) from tasks) as total_task
FROM tasks
  JOIN (SELECT * FROM tasks ORDER BY tasks.id LIMIT ? OFFSET ?) AS T 
    ON tasks.id = t.id
  LEFT JOIN pages ON tasks.id pages.task_id;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-19
    • 2017-11-17
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 2012-03-14
    相关资源
    最近更新 更多