2012-07-10 60 views
4

考慮以下三個MySQL表更新tweets.spam柱:通過連接一個或兩個其他表

tweets      urls     tweets_urls 
--------------------------- --------------------- ---------------- 
tweet_id text   spam url_id host  spam tweet_id url_id 
--------------------------- --------------------- ---------------- 
    1  I love cnn.com 0  16 cnn.com 0  1  16 
    2  fox.com is fuk 0  17 fox.com 1  2  17 
    3  love me!  0        4  16 
    4  blah cnn.com 0 
    5  nice fox.com 0 

我想根據tweets_urls更新tweets.spam,這意味着查詢的輸出應該是

tweets 
--------------------------- 
tweet_id text   spam 
--------------------------- 
    1  I love cnn.com 0 <-- tweets_urls tells me tweet_id 1 has url_id 16 
    2  fox.com is fuk 1  in it, and the urls-table tells me that url 16 
    3  love me!  0  is not spam (spam = 0) 
    4  blah cnn.com 0 
    5  nice fox.com 1 

我希望自己清楚。我一直在擺弄它,現在有這樣的事情。我知道這不可能是正確的,但不知道如何重新開始。你做?

UPDATE tweets SET spam = (
    SELECT spam FROM urls 
    LEFT JOIN tweets_urls 
    WHERE urls.url_id = tweets_urls.url_id 
) 

任何幫助,將不勝感激:-)

回答

1

爲您給出的數據,該查詢返回的結果集...

SELECT t.tweet_id 
    , t.text 
    , IFNULL(s.spam,t.spam) AS spam 
    FROM tweets t 
    LEFT 
    JOIN (SELECT tu.tweet_id, MAX(u.spam) AS spam 
      FROM tweets_urls tu 
      JOIN urls u ON u.url_id = tu.url_id 
      WHERE u.spam = 1 
      GROUP BY tu.tweet_id 
     ) s 
    ON s.tweet_id = t.tweet_id 

但是我們已經取得了什麼時候是tweets_url多行對於給定的tweet_id應該怎樣做一些假設,或當沒有匹配的網址等

如果你想要的是一個tweet標記爲 「spam = 1」,只要發現該推文與任何標記爲「spam = 1「,否則,鳴叫應標記爲」垃圾郵件= 0「...

這將設置垃圾郵件列在微博中的每一行,根據該規則...

UPDATE tweets t 
    LEFT 
    JOIN (SELECT tu.tweet_id, MAX(u.spam) AS spam 
      FROM tweets_urls tu 
      JOIN urls u ON u.url_id = tu.url_id 
      WHERE u.spam = 1 
      GROUP BY tu.tweet_id 
     ) s 
    ON s.tweet_id = t.tweet_id 
    SET t.spam = IFNULL(s.spam,0) 

如果你想獨自離開垃圾柱(把它設置爲任何它被設置爲)並且只想更新其中的值是當前設置爲0,應設置爲1的行,要按照「匹配URL有垃圾= 1」,你可以這樣做:

UPDATE tweets t 
    JOIN (SELECT tu.tweet_id 
      FROM tweets_urls tu 
      JOIN urls u ON u.url_id = tu.url_id 
      WHERE u.spam = 1 
      GROUP BY tu.tweet_id 
     ) s 
    ON s.tweet_id = t.tweet_id 
    SET t.spam = 1 
WHERE t.spam = 0 

注意,謂詞tweets表中,我們只會更新當前垃圾郵件設置爲零的行。並且請注意,我們不需要參考urls表中的垃圾郵件列的值,我們已經測試過它等於1,所以我們可以在將值分配給tweets.spam時使用字面值1柱。還要注意我們正在做一個INNER JOIN(而不是一個LEFT OUTER JOIN),所以我們再次只會更新將被賦值爲1的行。


+1

因此,如果我理解正確,如果tweets-table有一行文本不包含與urls-table中任何url匹配的URL,tweets.spam設置爲零(0)?這是我的想法,然後它會被留下,因爲tweets.spam在這種情況下已經設置爲0(參見默認表,其中tweets.spam = 0,對於所有行) – Pr0no 2012-07-10 19:57:53

+1

@ Pr0no:是的。我已經更新了我的答案,添加了另一個語句,只更新當前垃圾郵件= 0,應該設置爲垃圾郵件= 1(根據與垃圾郵件= 1匹配的網址)的行。哪一個最適合你。這就是爲什麼我小心地解釋原始查詢正在做什麼,在推文的每一行上設置垃圾郵件。在MySQL中,分配與當前值相同的值的更新不會真正修改該行。 (這與Oracle等其他數據庫不同,它記錄了與更改相同值的分配。) – spencer7593 2012-07-10 20:09:26

3

你忘了相關子選擇回tweets表,並在您的ON條款加入:

UPDATE tweets SET spam = (
    SELECT spam FROM urls 
    LEFT JOIN tweets_urls ON urls.url_id = tweets_urls.url_id 
    WHERE tweets_urls.tweet_id = tweets.tweet_id 
) 

您還沒有定義該怎麼辦:

  • 沒有條目的tweet_id
  • 有在tweets_urls多個條目的tweet_id

最後,作爲一個側面說明,你確定要及時更新這個樣子?這聽起來更像是你想要使用視圖或存儲過程產生的東西 - 除非urlstweets_urls只是你現在添加的表,以幫助填充tweets表,然後稍後放下。

+2

你不需要限制1嗎? (以防萬一?) – jcho360 2012-07-10 18:34:17

+0

@ jcho360是的,如果這是所需的行爲。也不知道如何處理tweet_ids 3和5的NULL。 – 2012-07-10 18:36:33

+0

lol,這就是問題,當我們不使用sqlfiddle給每個人看結果 – jcho360 2012-07-10 18:39:02