4

考虑以下三个 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
)

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

4

2 回答 2

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_urlstweet_id没有条目
  • tweets_urlstweet_id中有多个条目

最后,作为旁注,您确定要像这样进行更新吗?这听起来更像是您想使用视图或存储过程生成的东西 - 除非urls并且tweets_urls只是您现在添加的表以帮助填充tweets表,然后稍后再删除。

于 2012-07-10T18:33:41.097 回答
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,当 tweets_url 中的行超过一行,或者没有匹配的 url 等时,我们已经做了一些假设。

如果您想要的是将推文标记为“垃圾邮件=1”,只要发现该推文与任何标记为“垃圾邮件=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

请注意,推文表上的谓词,我们只会更新垃圾邮件当前设置为零的行。请注意,我们不需要从 urls 表中引用 spam 列的值,我们已经在测试它是否等于 1,因此我们可以在将值分配给 tweets.spam 时使用文字 1柱子。另请注意,我们正在执行 INNER JOIN(而不是 LEFT OUTER JOIN),因此,我们将只更新将被分配值 1 的行。


于 2012-07-10T19:08:17.703 回答