I have two tables, one which I will call D and one which I will call S, with a 1:N relationship between D and S. I currently have the following query that runs on these two:
SELECT d.*, s.*
FROM d
LEFT JOIN s ON s.d_id = d.id
WHERE coalesce(:status, d.status) = d.status
Now, this works well, but I would like to be able to filter on s.block_start
and s.block_end
, which are date times. That seems straightforward, but my goal is to filter out any row in D that corresponds to a row in S which doesn’t fall within the date time bounds I set. My first thought was to join the above with the following query:
SELECT id
FROM (
SELECT d.id, MIN(s.block_start), MAX(s.block_end)
FROM d
LEFT JOIN s ON s.d_id = d.id
GROUP BY d.id
) WHERE block_start >= :start AND block_end <= :end
but this seems like a very inefficient query for what I’m trying to do. Does anyone know of the best-practice way to achieve this result?
2
Answers
If you want get only d.id you can take s.d_id (d.id=s.d_id) without JOIN.
Try
Case when d.id is exists in D and not exists s.d_id then you will still filter such condition rows by date range(id,null,null). Therefore, join with
d
is not needed.Case when you want some like d.* (several columns from
d
)try
There using
LEFT
orINNER
join – the choice depends on the expected result.inner join
matches your current query.With the growth of N in the ratio d:s (1:N), the relative efficiency of such a query will be better.
Applying a date range filter before grouping and before join is also preferable, the more so the narrower this filter is.
Your query reduces to a
HAVING
clause:demo at db<>fiddle
And it’s not really that inefficient, as long as you have this type of index in place:
Thing is, the description of your desired logic doesn’t really match your code, or its reduced version:
Not falling within could be:
Among others. On top of that, you’re aggregating, so the code accepts all
d
‘s that have at least ones
above the lower bound, and another, not necessarily the same, which is under the upper bound.There might be a faster index+query setup, depending on what exactly you’re aiming to catch/skip.