我有一个LEFT OUTER JOIN链,只适用于90%的情况。
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
但我想得到这个结果:
2017-01-01, Test1, 1
2017-01-02, NULL, NULL
2017-01-03, NULL, NULL
根据我的理解,periods.id IS NULL
与最后一个条目不匹配,因为period #2
的{{1}}为federal_state_id
。
如何更改SQL-Query以获得我想要的结果?
答案 0 :(得分:2)
如果将句点条目上的条件移动到连接条件,它们将不会成为与插槽连接的集合的一部分,从而为NULL
和{{1}生成所需的name
}}。因此,将要加入的集合仅包含:
federal_state_id
因此,可以返回日期的每个条目(范围内的条件除外)。该查询将如下所示:
periods:
id, starts_on, ends_on, name, federal_state_id, country_id
1, 2017-01-01, 2017-01-01, Test1, 1, NULL
请注意,不再需要条件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;
,因为条件应用的条件仅包含插槽和句点,其中每个句点条目都将具有id值,因为它是主键。由于插槽和句点由左连接插槽连接,因此不会删除句点表中没有匹配项。
在原始查询中,您首先加入了句点的所有条目(如果ID匹配),然后删除所有没有所需periods.id IS NULL
或country_id
的条目。这删除了federal_state_id
中匹配但不符合条件的日期。
答案 1 :(得分:1)
我总是建议格式化SQL语句。错误更容易找到。
将条件移动到连接,如:
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
;