通过连接一个或两个其他表来更新tweets.spam列

时间:2012-07-10 18:27:19

标签: mysql

考虑以下三个MySQL表:

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
)

任何帮助将不胜感激: - )

2 个答案:

答案 0 :(得分: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
)

在以下情况下,您还没有定义要执行的操作:

  • tweets_urls中没有针对tweet_id
  • 的条目
  • tweets_urls中有多个条目用于tweet_id

最后,作为旁注,你确定你想要像这样更新吗?这听起来更像是你想要使用视图或存储过程生成的东西 - 除非urlstweets_urls只是你现在添加的表,以帮助填充tweets表然后会丢弃后面。

答案 1 :(得分: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

但是对于给定的tweet_id,或者当没有匹配的url等时,我们已经对tweets_url中的多行应该做什么做了一些假设。

如果您想要的是将推文标记为 “spam = 1”,只要发现该推文与任何标记为“spam = 1”的网址相关,否则,该推文应标记为“spam = 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有spam = 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的行。