繁体   English   中英

左外联接为IS NULL

[英]LEFT OUTER JOIN with IS NULL

我在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

SQL查询

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

据我了解,由于最后一个条目的federal_state_id periods.id IS NULL不匹配,因为存在period #2federal_state_id2

如何更改SQL查询以获取所需的结果?

如果将期间条目上的条件移至加入条件,则它们将不属于与槽加入的集合,从而为namefederal_state_id产生所需的NULL 因此,将要加入的集合将仅包含:

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;

请注意,不再需要conditions.id periods.id IS NULL条件,因为将条件套用到仅包含时隙和时间段的集合,其中每个时间段条目都是主键,因此每个id条目将具有一个id值。 并且,由于插槽和期间由左连接插槽连接,因此不会删除期间表中不匹配的内容。

在您的原始查询中,您首先加入了period的所有条目(如果id匹配),然后删除了所有没有所需country_idfederal_state_id 这将删除period有匹配但不符合条件的日期。

我总是建议格式化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
       ;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM