0

I found a similar question but it didn't satisfy my answer: SQL: Select records where ALL joined records satisfy some condition

I have two tables, orders and shipments

orders have_many shipments

shipments have attribute status open/closed

I would like to query orders, where all of its shipments are closed:

Assuming table of:

  • order1, 2 shipments: 1open, 1closed
  • order2, 3 shipments: 1open, 2closed
  • order3, 1 shipments: 0open, 1closed
  • order4, 2 shipments: 0open, 2closed

Running the query returns records for order3 and order4

I am currently doing this with N+1 using application code, I'd like to just implement in SQL.

Blair Anderson
  • 19,463
  • 8
  • 77
  • 114

2 Answers2

2

Let's look for all orders for which there does not exist any shipment (matching that order) with a status other than closed.

Order.where("NOT EXISTS(SELECT 1 FROM shipments WHERE shipments.order_id = orders.id AND status != 'closed')"
Marcin Kołodziej
  • 5,253
  • 1
  • 10
  • 17
1

demo:db<>fiddle

Aggregate the status and then you can filter with the ALL operator which checks if all array elements fit the condition.

SELECT order_id
FROM (
    SELECT order_id, array_agg(status) status
    FROM shipments
    GROUP BY order_id
) s
WHERE 'closed' = ALL(status)
S-Man
  • 22,521
  • 7
  • 40
  • 63
  • DBfiddle looks great. but those tables are not matching my tables. – Blair Anderson Sep 28 '18 at 18:44
  • @BlairAnderson It would be great if you could add your tables to your question. I changed the fiddle and the query. The idea remains the same :) – S-Man Sep 28 '18 at 18:49
  • [SQL fiddle](https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=7b445ae081c809f07102653b0f69d476) for speed comparison. `NOT EXISTS` is 2.5 faster on average on the 100 data set (the difference will probably grow due to index usage). – Marcin Kołodziej Sep 28 '18 at 19:13
  • @MarcinKołodziej really nice. Even my second idea `DISTINCT ON` is not as fast as yours. https://dbfiddle.uk/?rdbms=postgres_9.6&fiddle=2a8893ec5f538da7e66fffb293b1d149 Maybe one can tweak a little bit with certain indexes but this depends on the real case. – S-Man Sep 28 '18 at 19:30