2010-03-20 51 views
1

我有一個通過連接表Info連接到表的文章的主表只有少量條目的標記。我想分割文章表,通過刪除行或創建一個只有我想要的條目的新表,基於沒有鏈接到某個標記。有幾百萬篇文章。我怎樣才能做到這一點?基於連接分割表的SQL語句

並非所有的文章都有任何標籤,有些標籤有很多。

例子:

table Articles 
    primary_key id 
table Info 
    foreign_key article_id 
    foreign_key tag_id 
table Tags 
    primary_key id 

這是很容易對我來說,隔離那些有比賽馬上蝙蝠的文章,所以我想也許我能做到這一點,然後使用一個NOT IN語句,但就是如此緩慢的運行還不清楚它是否會完成。我這樣做了這些命令:

INSERT INTO matched_articles SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 
INSERT INTO unmatched_articles SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m); 

如果它有所作爲,我在Postgres上。

回答

1
INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

INSERT INTO unmatched_articles 
SELECT * FROM articles a WHERE a.id NOT IN (SELECT m.id FROM matched_articles m); 

這裏有太多的錯誤,我不知道從哪裏開始。在第一次插入時確定您不需要左連接,實際上您實際上沒有連接。它應該是

INSERT INTO matched_articles 
SELECT * FROM articles a INNER JOIN info i ON a.id = i.article_id WHERE i.tag_id = 5; 

要是你需要一個LEFT JOIN,你將不得不

INSERT INTO matched_articles 
SELECT * FROM articles a LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5; 

當你把東西從左側的右側比尋找空加入到where子句(其它值),然後將其轉換爲內部聯接,因爲它必須符合該條件,因此在右側表格中沒有匹配的記錄被取消。

現在第二個聲明可以用左連接的一個特例來完成,儘管你有什麼工作。

INSERT INTO matched_articles 
SELECT * FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND i.tag_id = 5 
WHERE i.tag_id is null 

這將給你所有的信息表中的記錄,除了那些匹配的文章表。

現在接下來的事情,你不應該在沒有指定你想要插入的字段的情況下編寫插入staises。您也不應該使用select *編寫select語句,特別是如果您有連接。這通常是草率的,懶惰的編碼,應該修復。如果有人改變了其中一張桌子的結構而不是另一張桌子的結構呢?這種事情對於維護不利,而且在使用連接的選擇語句的情況下,它將兩次返回一個列(連接列),這就浪費了服務器和網絡資源。懶惰的編碼太懶,指定你需要什麼,只有你需要什麼。因此,擺脫習慣,不要再做任何生產守則。

如果您當前的帖子太慢,您也可以使用正確的索引修復它。這兩個表上的id字段是否被索引?另一方面,如果有幾百萬篇文章,插入它們需要時間。通常情況下,一次最多可以批量處理50000個(如果這需要很長時間,則更少)。只要執行insert ina循環選擇最前面的XXX記錄,然後循環直到受影響的行數爲無。

+0

非常感謝您的幫助。我真的剛剛開始使用數據庫,並且您的反饋非常有幫助。對於匹配,您的插入語句運行得非常好,幾秒鐘內就完成了,而我之前的方法已經運行了幾個小時。 – 2010-03-20 19:45:46

1

除了第一個應該是內連接而不是左連接外,您的查詢看起來不錯。如果你想別的試一下,考慮一下:

INSERT INTO matched_articles 
SELECT * 
FROM articles a 
INNER JOIN info i ON a.id = i.article_id 
WHERE i.tag_id = 5; 

INSERT INTO unmatched_articles 
SELECT * 
FROM articles a 
LEFT JOIN info i ON a.id = i.article_id AND a.id <> 5 
WHERE a.id IS NULL 

這可能會更快,但說真的,你有什麼可能是好的,如果你只有做一次。

1

不確定,如果Postgres有一個臨時表的概念。
這也是如何做到的。

CREATE Table #temp 
AS SELECT A.ID, COUNT(i.*) AS Total 
FROM Articles A 
LEFT JOIN info i 
ON A.id = i.Article_ID AND i.Tag_ID = 5 
GROUP BY A.ID 

INSERT INTO Matched_Articles 
SELECT A.* 
FROM Articles A INNER JOIN #temp t 
ON A.ID = t.Article_ID AND T.Total = 0 

DELETE FROM #Temp 
WHERE Total = 0 

INSERT INTO UnMatched_Articles 
SELECT A.* 
FROM Articles AINNER JOIN #temp t 
ON A.ID = t.Article_ID 

請注意,我沒有使用任何編輯器來嘗試此操作。
我希望這給你提示我將如何處理這個問題。