2014-06-17 20 views
0

我有兩個表:AP和表AP supervisory visits,分別爲一對多關係。 AP supervisory visits沒有主鍵或唯一索引(因此可能有點難以使用),而「IN()」函數沒有簡單的時間。在表中缺少唯一行或主鍵的情況下使用NOT IN()mysql

AP

+------------------------------+-------------+------+-----+---------+-------+ 
| Field      | Type  | Null | Key | Default | Extra | 
+------------------------------+-------------+------+-----+---------+-------+ 
| HID       | varchar(50) | NO | PRI | NULL |  | 
| yr       | varchar(50) | NO | PRI | NULL |  | 
| mo       | varchar(50) | NO | PRI | NULL |  | 

AP supervisory visits

+------------------+-------------+------+-----+---------+-------+ 
| Field   | Type  | Null | Key | Default | Extra | 
+------------------+-------------+------+-----+---------+-------+ 
| HID    | varchar(50) | YES | MUL | NULL |  | 
| yr    | varchar(50) | YES |  | NULL |  | 
| mo    | varchar(50) | YES |  | NULL |  | 
| exported   | datetime | YES |  | NULL |  | 
| visitor name  | varchar(50) | YES |  | NULL |  | 
| title   | varchar(50) | YES |  | NULL |  | 
| reason for visit | varchar(50) | YES |  | NULL |  | 
| number of visits | int(11)  | YES | MUL | 0  |  | 
+------------------+-------------+------+-----+---------+-------+ 

我有在AP約8000條記錄和1700個獨特的記錄AP supervisory visits(使用HID,年,月)。我希望AP表中AP supervisory visits表中沒有'子女'的所有記錄。在Stakeoverflow上使用其他文章我得出結論,我應該使用「NOT IN()」。這適用於我的幾個有類似關係表,但不是這個時候(請注意最後查詢倒數,它缺乏NOT):

mysql> SELECT HID, yr, mo FROM AP 
    -> WHERE (HID, yr, mo) NOT IN(SELECT HID, yr, mo FROM `AP supervisory visits`); 
Empty set (0.34 sec) 

mysql> SELECT HID, yr, mo FROM AP 
    -> WHERE (HID, yr, mo) NOT IN(SELECT DISTINCT HID, yr, mo FROM `AP supervisory visits`); 
Empty set (0.47 sec) 

mysql> SELECT HID, yr, mo FROM AP 
    -> WHERE (HID, yr, mo) NOT IN(SELECT DISTINCT * FROM (SELECT DISTINCT HID, yr, mo FROM `AP supervisory visits`) AS temp); 
Empty set (3.04 sec) 

mysql> SELECT HID, yr, mo FROM AP 
    -> WHERE (HID, yr, mo) IN(SELECT DISTINCT HID, yr, mo FROM `AP supervisory visits`) LIMIT 5; 
+-----+------+----+ 
| HID | yr | mo | 
+-----+------+----+ 
| 109 | 2011 | 03 | 
| 109 | 2012 | 05 | 
| 109 | 2012 | 06 | 
| 110 | 2010 | 11 | 
| 110 | 2010 | 12 | 
+-----+------+----+ 
5 rows in set (0.00 sec) 

因爲創建的臨時表我已經與所有不同組合HID,年,月,但我寧願沒有臨時表共。上面的第三個查詢應該是在內存中創建一個具有不同值的臨時表(這是我知道的醜),但似乎並非如此。

我的「治標不治本」:

mysql> CREATE TABLE myTempAPSup SELECT DISTINCT HID, yr, mo FROM `AP supervisory visits`; 
mysql> ALTER TABLE myTempAPSup ADD PRIMARY KEY(HID, yr, mo); 
mysql> SELECT HID, yr, mo FROM AP 
    -> WHERE (HID, yr, mo) NOT IN (SELECT HID, yr, mo FROM myTempAPSup) LIMIT 5; 
+-----+------+----+ 
| HID | yr | mo | 
+-----+------+----+ 
| 109 | 2010 | 01 | 
| 109 | 2012 | 01 | 
| 109 | 2012 | 02 | 
| 109 | 2012 | 03 | 
| 109 | 2012 | 04 | 
+-----+------+----+ 
5 rows in set (0.00 sec) 

有沒有辦法,沒有從這樣的製作粗劣表「孩子」,讓行?我假設我的麻煩源於缺少唯一/主鍵,但我是否缺少其他一些語法上的「陷阱」?

回答

2

如果您來自Oracle背景,左連接,然後檢查null的想法可能看起來很奇怪,但這種解決方案很快就會變得很快,因爲你沒有掃描連接表中的每條記錄,另一種方法是使用不存在的相關子查詢條款。

SELECT a.HID 
    , a.yr 
    , a.mo 
    FROM AP a 
WHERE NOT EXISTS (
     SELECT v.HID 
     FROM `AP supervisory visits` v 
     WHERE v.HID = a.HID 
      AND v.yr = a.yr 
      AND v.mo = a.mo 
) 
+0

由於茶卡,幾乎工程,只是v.HID替換ap.HID(StackOF不會讓我做編輯,因爲它是太少字符)。我很困惑,雖然**如何存在()**知道檢查所有三列匹配,如果我們只是選擇HID。(我已經運行了查詢,並確實拉回與上述左連接相同數量的結果)。 –

+0

看起來像** EXISTS()**對於頂部查詢中提到的列是簡單正確的/不正確的。 SELECT語句是無關緊要的。這可以提供最好的解決方案,因爲我可以將這些解決方案堆疊到多個子表中。不幸的是,這是令人難以置信的CPU密集型,但不需要對數據庫做任何改變就可以工作。再次感謝Chaka: –

+0

「看起來EXISTS()對於頂部查詢中提到的列是簡單的/不真實的。」不,那不是真的。相反'WHERE v.HID = a.HID和v.yr = a.yr AND v.mo = a.mo'定義了要檢查的列。嘗試在這兩個表的這三列上添加非唯一索引並再次檢查性能。 –

1

您可以使用LEFT JOIN並檢查是否存在子記錄,當子記錄不存在時爲空。

select a.HID, a.yr, a.mo 
from AP a 
left join `AP supervisory visits` b on a.HID = b.HID and a.yr = b.yr and a.mo = b.mo 
where b.yr is null; 
1

下面是從AP那些在AP supervisory visits不「匹配」行獲得行的一種方式:

SELECT a.HID 
    , a.yr 
    , a.mo 
    FROM AP a 
    LEFT 
    JOIN `AP supervisory visits` v 
    ON v.HID = a.HID 
    AND v.yr = a.yr 
    AND v.mo = a.mo 
WHERE v.HID IS NULL 

這是一個左外連接,以獲得來自AP的所有行,以匹配行一起從AP supervisory visits。 「竅門」是WHERE條款中的謂詞...我們排除了所有匹配的行。 (我們正在檢查一個我們知道的列是否爲NULL,如果匹配的話;列的唯一方法是NULL,如果沒有匹配

相關問題