I have a at LEFT OUTER JOIN chain which only works for 90% of the cases.
days:
id, date_value
1, 2017-01-01
2, 2017-01-02
3, 2017-01-03
periods:
id, starts_on, ends_on, name, federal_state_id, country_id
1, 2017-01-01, 2017-01-01, Test1, 1, NULL
2, 2017-01-03, 2017-01-03, Test2, 2, NULL
slots:
id, days_id, periods_id
1, 1, 1
2, 3, 2
SELECT days.date_value, periods.name, periods.federal_state_id
FROM days
LEFT OUTER JOIN slots ON (days.id = slots.day_id)
LEFT OUTER JOIN periods ON (slots.period_id = periods.id)
WHERE days.date_value >= '2017-01-01' AND
days.date_value <='2017-01-03' AND
(periods.id IS NULL OR periods.country_id = 1 OR
periods.federal_state_id = 1)
ORDER BY days.date_value;
2017-01-01, Test1, 1
2017-01-02, NULL, NULL
But I'd like to get this result:
2017-01-01, Test1, 1
2017-01-02, NULL, NULL
2017-01-03, NULL, NULL
As fare as I understand it the periods.id IS NULL
doesn't match for the last entry because there is period #2
with a federal_state_id
of 2
.
How do I have to change the SQL-Query to get the result I want?
If you move the condition on the periods entries to the join condition, they will not be part of the set that is joined with the slots, producing the desired NULL
for name
and federal_state_id
. So the set that will be joined will only contain:
periods:
id, starts_on, ends_on, name, federal_state_id, country_id
1, 2017-01-01, 2017-01-01, Test1, 1, NULL
As such, every entry of date can be returned (except for the condition on the range). The query would then look like this:
SELECT
days.date_value,
periods.name,
periods.federal_state_id
FROM days
LEFT OUTER JOIN slots
ON (days.id = slots.day_id)
LEFT OUTER JOIN periods
ON (slots.period_id = periods.id) AND
((periods.country_id = 1 OR
periods.federal_state_id = 1))
WHERE
days.date_value >= '2017-01-01' AND
days.date_value <='2017-01-03'
ORDER BY
days.date_value;
Please notice that the condition periods.id IS NULL
is not needed any more as the set the conditions are applied to consist of only slots and periods where every period entry will have a value for id as it is the primary key. And as slots and periods are joined by a left join slots, having no match in the periods table are not removed.
In your original query you first joined all the entries of period (if the id matched) and then removed all the entries that didn't have the desired country_id
or federal_state_id
. This removed the dates that did have a match in period
but did not meet the condition.
I always recomend formating SQL statements. Errors are easier to find.
Move the conditions to the joins like:
SELECT days.date_value
,periods.name
,periods.federal_state_id
FROM dbo.days
LEFT OUTER JOIN dbo.slots
ON days.id = slots.days_id
LEFT OUTER JOIN dbo.periods
ON slots.periods_id = periods.id
AND (
periods.country_id = 1
OR periods.federal_state_id = 1
)
WHERE days.date_value >= '2017-01-01'
AND days.date_value <='2017-01-03'
ORDER BY days.date_value
;
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.