2012-03-07 81 views
1

我有兩個表,其中包含名稱以及與這些名稱相關的日期時間表。我正在嘗試獲取過去2個月內從未計劃或未安排的所有名稱的列表。在子查詢中選擇列的位置是否爲空

SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON n.id = s.nameid 
    WHERE s.nameid IS NULL 
     OR s.nameid NOT IN (SELECT nameid 
          FROM schedule 
          WHERE date > NOW() - INTERVAL 2 MONTH) 
GROUP BY n.id 

當我運行這個查詢時,MySQL接管了CPU並且沒有響應。

當我把它更改爲這些我得到的結果,但只有結果的一半我要找:

SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON n.id = s.nameid 
    WHERE s.nameid IS NULL 
GROUP BY n.id 

    SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON n.id = s.nameid 
    WHERE s.nameid NOT IN (SELECT nameid 
          FROM schedule 
          WHERE date > NOW() - INTERVAL 2 MONTH) 
GROUP BY n.id 

我不知道如何得到這個查詢工作,返回所有的結果,或者爲什麼它接管了CPU。

+0

你爲什麼不只是'union'在一起? – gangreen 2012-03-07 05:29:10

+0

請注意,如果比較的列不能爲NULL,則LEFT JOIN/IS NULL在MySQL上只會更快:http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left -join-is-null-mysql/ – 2012-03-07 05:37:51

回答

1

OR是一個臭名昭着的窮人,在我能想到的每個數據庫中。一個UNION如果經常一個更好的選擇:

SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON n.id = s.nameid 
    WHERE s.nameid IS NULL 
GROUP BY n.id 
UNION 
    SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON n.id = s.nameid 
    WHERE s.nameid NOT IN (SELECT nameid 
          FROM schedule 
          WHERE date > NOW() - INTERVAL 2 MONTH) 
GROUP BY n.id 

UNION將刪除重複的 - 如果沒有關於重複的關注,使用UNION ALL(它的速度更快,因爲它不會刪除重複項)。

此外,後者查詢具有針對WHERE子句中的OUTER JOIN'd表的條件 - 此條件在 JOIN後應用。你可能會用得到不同的結果:

SELECT n.name, MAX(s.date) 
    FROM names n 
LEFT JOIN schedule s ON s.nameid = n.id 
        AND s.nameid NOT IN (SELECT nameid 
              FROM schedule 
              WHERE date > NOW() - INTERVAL 2 MONTH) 
GROUP BY n.id 

在上面的例子中,標準將的OUTER JOIN之前應用。對於INNER JOIN,這可以忽略 - 任何一個點的標準都是相同的。

+0

很好的答案,感謝您的幫助。不知道爲什麼我沒有想到聯盟,但這正是我需要的。 – 2012-03-08 03:37:06

0

不知道你完整的模式,是有什麼錯

SELECT n.name, max(s.date) 
    FROM names n 
LEFT JOIN schedule s 
     ON n.id = s.nameid 
    WHERE s.nameid IS NULL 
     OR s.date <= DATE_SUB(CURDATE(), INTERVAL 2 MONTH) 
GROUP BY n.id 
+0

這可以返回與OP的意圖不同的結果(通過查詢來判斷)。您的查詢只會排除2個月以上的行,但OP的版本將排除在2個月以前的行中找到的*項*(並且也可能在新行中找到,但仍將被排除)。 – 2012-03-07 05:53:52