簡體   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