Matthod357
Matthod357

Reputation: 31

Limit and offset a search query that has a left join

I've got two tables: tasks and pages. The first page has a column that references the second table multiple times, called page_number. I want to get all fields of the first table and all page number values for the same tasks.id. My query for getting this data is as such:

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);

This works, and I get an output like so:

      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

But I've come upon other requirements: I need to get a total count of the TASKS table as well in the same query (for pagination in the front-end), and I need to be able to search the resulting table (i.e look for any substring in the table) . To search the table, I did this:

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 ?

I do get results, but LIMIT and OFFSET work on the joined table before the WHERE clause, so I set LIMIT to something like 10 and OFFSET to 5, try to look for a record that's in the first 5 records and get no results because the matching records are further on in the original table:

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

Actual output:

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

Expected Output:

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

How should I structure this query so I get all records that match the WHERE clause, getting at most limit tasks?

I'm using PostgreSQL, btw. Thanks in advance for any help.

Upvotes: 3

Views: 2960

Answers (1)

user330315
user330315

Reputation:

You could add that count to the column list:

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;

Upvotes: 1

Related Questions