2013-02-23 64 views
2

如果我有一個表t1,它看起來像記錄在項目,大小和日期組合上是唯一的;選擇在一個日期但不在另一個日期上的記錄?

item size date 
1234 S 2013-02-11 
1234 M 2013-02-11 
1234 L 2013-02-11 
9999 S 2013-02-11 
9999 M 2013-02-11 
9999 L 2013-02-11 
1234 S 2013-02-13 
1234 M 2013-02-13 
1234 L 2013-02-13 
9999 S 2013-02-13 
9999 M 2013-02-13 

如何檢索2013-02-13與2013-02-11相比缺少的項目和尺寸?

我找的是回報,

item size 
9999 L 

我都試過;

SELECT ta.item, 
     ta.size 
FROM t1 ta 
    LEFT JOIN t1 tb 
     ON ta.item = tb.item 
      AND ta.size = tb.size 
WHERE ta.date = '2013-02-11' 
    AND tb.date = '2013-02-13' 
    AND tb.size IS NULL 

SELECT item, size 
FROM t1 
WHERE t1.date = '2013-02-11' 
    AND NOT EXISTS (
        SELECT item, size 
        FROM t1 
        WHERE t1.date = '2013-02-13' 
       ) 

都返回空集。

我設法讓這個工作的唯一方法是使用臨時表;

CREATE temporary table temp1 
SELECT * FROM t1 WHERE date = '2013-02-11'; 

CREATE temporary table temp2 
SELECT * FROM t1 WHERE date = '2013-02-13'; 

SELECT temp1.item, temp1.size FROM temp1 
    LEFT JOIN temp2 
     ON temp1.item = temp2.item AND temp1.size = temp2.size 
WHERE temp2.size IS NULL 

臨時表是不可能的。我怎樣才能實現這一點,而不使用臨時表?

非常感謝,

(請溫柔,我剛開始出來的!)

回答

1

使用聚合查詢:

select item, size 
from t1 
group by item, size 
having sum(case when date = '2013-02-11' then 1 else 0 end) = 1 and 
     sum(case when date = '2013-02-13' then 1 else 0 end) = 0 

這是查詢「組內羣體」的一個例子。通過改變having條款,您可以在需要滿足的條件下擁有很大的靈活性。例如:

having sum(case when date = '2013-02-11' then 1 else 0 end) = 0 or 
     sum(case when date = '2013-02-13' then 1 else 0 end) = 0 

將返回數據中存在的組合,但在任一天丟失。

+0

+1,但如果您在分組之前將行限制爲('2013-02-11','2013-02-13')'中的日期,則可以簡化兩種情況下的「有」條件。 – 2013-02-23 16:36:44

+0

@AndriyM。 。 。是的,對於這個特定的問題,這是一個好主意。 – 2013-02-23 16:37:20

+0

謝謝Gordon,儘管我不得不承認我不太明白 - 我會研究這個,因爲額外的靈活性可能會非常有用 – 2013-02-24 07:43:57

4
SELECT a.* 
FROM 
     (
      SELECT item, size 
      FROM tableName 
      WHERE date = '2013-02-11' 
     ) a 
     LEFT JOIN 
     (
      SELECT item, size 
      FROM tableName 
      WHERE date = '2013-02-13' 
     ) b ON a.item = b.item AND 
       a.size = b.size 
WHERE b.size IS NULL 
+1

我投了票,但沒有必要的子查詢。把2/13放在ON上;和2/11在WHERE。 – 2013-02-23 16:31:46

+0

非常感謝JW,完美無缺! – 2013-02-24 07:40:23

0

你也可以試試這個簡單的查詢

SELECT item, size FROM dbo.Table_1 WHERE date = '2013-02-11' 
EXCEPT 
SELECT item, size FROM dbo.Table_1 WHERE date = '2013-02-13' 
+0

不幸的是,MySQL不支持'INTERSECT和EXCEPT'運算符。 – Ambrose 2013-02-23 14:37:55

+0

嗨Nitesh,我應該說我使用mySQL,無論如何。 – 2013-02-24 07:53:29

0

其他人已經爲你提供了有效的解決方案,而這篇文章僅僅解決了你失敗的嘗試,解釋了什麼是失蹤以及如何修復。

這個查詢

SELECT ta.item, 
     ta.size 
FROM t1 ta 
    LEFT JOIN t1 tb 
     ON ta.item = tb.item 
      AND ta.size = tb.size 
WHERE ta.date = '2013-02-11' 
    AND tb.date = '2013-02-13' 
    AND tb.size IS NULL 

失敗,因爲有一個矛盾的WHERE子句。該查詢試圖找到一行,其中tb.size爲NULL,這意味着tb實例與ta之一不匹配,tb.date是一個特定值。現在,如果tb中沒有匹配項,則其所有列將作爲NULL返回,其中包括tb.date,這意味着它不能等於值並且同時爲null。

顯然,你的意圖是不同的。您想將表的一個子集與另一個子集(同一個表中的其他子集)相連接。在這種情況下,定義要加入的子集的條件應放入ON子句中。也就是說,您沒有加入的唯一條件是兩個實例的itemsize列都匹配,但是在這些列的匹配條件是的組合條件下,另一個實例的date是特定值。所以,這是你應該擁有什麼,而不是:

SELECT ta.item, 
     ta.size 
FROM t1 ta 
    LEFT JOIN t1 tb 
     ON ta.item = tb.item 
      AND ta.size = tb.size 
      AND tb.date = '2013-02-13' 
WHERE ta.date = '2013-02-11' 
    AND tb.date = '2013-02-13' 
    AND tb.size IS NULL 

其他查詢

SELECT item, size 
FROM t1 
WHERE t1.date = '2013-02-11' 
    AND NOT EXISTS (
        SELECT item, size 
        FROM t1 
        WHERE t1.date = '2013-02-13' 
       ) 

似乎是混亂EXISTSIN結果。

首先,EXISTS是如何工作的。當子查詢返回一個非空行集合時,它返回true。無論哪列,只有行的存在都是重要的。如果沒有返回,則結果爲false。這樣一來,您的查詢內容是這樣的:

返回的每一行,其date'2013-02-11',而且沒有任何date = '2013-02-11'

雖然你可能是指由查詢是這樣說的:

返回的每一行,其date'2013-02-11'並且沒有相應行與相同itemsize'2013-02-11'date

也就是說,你需要歸屬關係 EXISTS的子查詢與主查詢,這意味着包括當前行的sizeitem到EXISTS測試。所以,這是修復可能是什麼樣子:

SELECT item, size 
FROM t1 ta 
WHERE ta.date = '2013-02-11' 
    AND NOT EXISTS (
        SELECT item, size 
        FROM t1 tb 
        WHERE tb.date = '2013-02-13' 
         AND ta.item = tb.item AND ta.size = tb.size 
       ) 

在另一方面,你可以重寫相同的查詢使用NOT IN而不是NOT EXISTS。在這裏:

SELECT item, size 
FROM t1 
WHERE date = '2013-02-11' 
    AND (item, size) NOT IN (
          SELECT item, size 
          FROM t1 
          WHERE date = '2013-02-13' 
          ) 

基本上說:

返回的每一行,其(item, size)對爲date = '2013-02-11'不在(item, size)對爲date = '2013-02-11'設置。

IN/NOT IN查詢可能常常看起來比其EXISTS/NOT EXISTS對口清晰。兩者是否會導致相同的查詢計劃是另一回事,您應該在決定使用哪種方法之前進行測試(但當然也適用於LEFT JOIN + WHERE IS NULL方法)。

+0

感謝這個Andriy。我曾希望有人會解釋我出錯的地方。你的文章真的很感謝。 – 2013-02-24 07:48:41

相關問題