简体   繁体   中英

using a single query to eliminate N+1 select issue

I want to return the last report of a given range of units. The last report will be identified by its time of creation. Therefore, the result would be a collection of last reports for a given range of units. I do not want to use a bunch of SELECT statements eg:

SELECT * FROM reports WHERE unit_id = 9999 ORDER BY time desc LIMIT 1
SELECT * FROM reports WHERE unit_id = 9998 ORDER BY time desc LIMIT 1
...

I initially tried this (but already knew it wouldn't work because it will only return 1 report):

'SELECT reports.* FROM reports INNER JOIN units ON reports.unit_id = units.id WHERE units.account_id IS NOT NULL AND units.account_id = 4 ORDER BY time desc LIMIT 1'

So I am looking for some kind of solution using subqueries or derived tables, but I can't just seem to figure out how to do it properly:

'SELECT reports.* FROM reports
WHERE id IN 
(
  SELECT id FROM reports
  INNER JOIN units ON reports.unit_id = units.id
  ORDER BY time desc
  LIMIT 1
) 

Any solution to do this with subqueries or derived tables?

The simple way to do this in Postgres uses distinct on :

select distinct on (unit_id) r.*
from reports r
order by unit_id, time desc;

This construct is specific to Postgres and databases that use its code base. It the expression distinct on (unit_id) says "I want to keep only one row for each unit_id ". The row chosen is the first row encountered with that unit_id based on the order by clause.

EDIT:

Your original query would be, assuming that id increases along with the time field:

SELECT r.*
FROM reports r
WHERE id IN (SELECT max(id)
             FROM reports
             GROUP BY unit_id
            );

You might also try this as a not exists :

select r.*
from reports r
where not exists (select 1
                  from reports r2
                  where r2.unit_id = r.unit_id and
                        r2.time > r.time
                 );

I thought the distinct on would perform well. This last version (and maybe the previous) would really benefit from an index on reports(unit_id, time) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM