Search code examples
sqlpostgresqlsubqueryinner-joinunion

Postgresql Select Rows where associated record with value X or Y does not exist


I have 3 tables:

Table        columns
---------------------
items        id, name
variations   id, item_id
images       id, variation_id, type

image has a variation and variation has an item

I want to find items which don't have images of type 4 or 5 (types are any integer 0..5 and cannot be null)

The below query works however it makes use of a UNION subquery with a NOT IN constraint which I believe is inefficient - the question is therefore what is a more efficient way to write this query.

SELECT DISTINCT i.id, i.name 
FROM items i 
INNER JOIN variations v 
  ON v.item_id = i.id 
INNER JOIN images vi 
  ON vi.variation_id = v.id 
WHERE i.id NOT IN (SELECT i.id FROM items i 
                  INNER JOIN variations v 
                    ON v.item_id = i.id 
                  INNER JOIN images vi 
                    ON vi.variation_id = v.id 
                  WHERE vi.type = 4
                  UNION
                  SELECT i.id FROM items i 
                  INNER JOIN variations v 
                    ON v.item_id = i.id 
                  INNER JOIN images vi 
                    ON vi.variation_id = v.id 
                  WHERE vi.type = 5)

Solution

Based on Gordons answer below final solution is:

select i.*
from items i
where not exists (select 1
                  from variations v join
                       images im
                       on v.image_id = im.id
                  where v.item_id = i.item_id and i.type in (4, 5)
                 )
and exists (select 1
                  from variations v join
                       images im
                       on v.id = im.variation_id
                       where v.item_id = i.id)

Solution

  • I want to find items which don't have images of type 4 or 5

    Based on your description, this sounds like not exists:

    select i.*
    from items i
    where not exists (select 1
                      from variations v join
                           images im
                           on v.image_id = im.id
                      where v.item_id = i.item_id and i.type in (4, 5)
                     );