0

我有一个这样的表(MySQL 5.0.x,MyISAM):

response{id, title, status, ...} (status: 1 new, 3 multi)

如果至少有 20 个标题相同,我想将所有响应的状态从 new ( status=1) 更新为 multi ( )。status=3

我有这个,但它不起作用:

UPDATE response SET status = 3 WHERE status = 1 AND title IN (
  SELECT title FROM (
   SELECT DISTINCT(r.title) FROM response r WHERE EXISTS (
     SELECT 1 FROM response spam WHERE spam.title = r.title LIMIT 20, 1)
   )
  as u)

请注意:

  • 我做嵌套选择以避免著名的You can't specify target table 'response' for update in FROM clause
  • GROUP BY出于性能原因,我不能使用。使用解决方案的查询成本LIMIT要好得多(但可读性较差)。

编辑:

  • 可以在 MySQL 中执行 SELECT FROM UPDATE 目标。在此处查看解决方案
  • 问题在于选择的数据完全错误。
  • 我发现的唯一可行的解​​决方案是GROUP BY

    UPDATE response SET status = 3
     WHERE status = 1 AND title IN (SELECT title 
                                      FROM (SELECT title 
                                              FROM response 
                                          GROUP BY title 
                                            HAVING COUNT(1) >= 20) 
    

作为派生响应)

谢谢你的帮助!:)

4

4 回答 4

1

当您尝试在一个查询中从同一个表中进行 UPDATE 和 SELECT 时,MySQL 不喜欢它。它与锁定优先级等有关。

以下是我将如何解决这个问题:

SELECT CONCAT('UPDATE response SET status = 3 ',
  'WHERE status = 1 AND title = ', QUOTE(title), ';') AS sql
FROM response
GROUP BY title
HAVING COUNT(*) >= 20;

此查询生成一系列 UPDATE 语句,其中嵌入了值得更新的引用标题。捕获结果并将其作为 SQL 脚本运行。

我知道GROUP BY在 MySQL 中经常会产生一个临时表,这可能会很昂贵。但这会破坏交易吗?您需要多久运行一次此查询?此外,任何其他解决方案也可能需要临时表。


我可以想出一种方法来解决这个问题而不使用GROUP BY

CREATE TEMPORARY TABLE titlecount (c INTEGER, title VARCHAR(100) PRIMARY KEY);

INSERT INTO titlecount (c, title)
 SELECT 1, title FROM response
 ON DUPLICATE KEY UPDATE c = c+1;

UPDATE response JOIN titlecount USING (title)
SET response.status = 3
WHERE response.status = 1 AND titlecount.c >= 20;

但这也使用了一个临时表,这就是为什么你一开始就尽量避免使用GROUP BY的原因。

于 2009-10-08T21:02:22.967 回答
0

这是 MySQL 的一个有趣的特性——我想不出一种方法可以在单个语句中完成它(GROUP BY 或没有 GROUP BY)。

您可以先将适当的响应行选择到临时表中,然后通过从该临时表中进行选择来进行更新。

于 2009-10-08T20:58:29.010 回答
0

您必须使用临时表:

create temporary table r_update (title varchar(10));

insert r_update
select title
  from response
group
    by title
having count(*) < 20;

update response r
left outer
  join r_update ru
    on ru.title = r.title
   set status = case when ru.title is null then 3 else 1;
于 2009-10-08T21:04:39.077 回答
0

我会写一些简单的东西,如下所示

UPDATE `response`, (
  SELECT title, count(title) as count from `response`
     WHERE status = 1
     GROUP BY title
  ) AS tmp
  SET response.status = 3
  WHERE status = 1 AND response.title = tmp.title AND count >= 20;

使用 GROUP BY 真的那么慢吗?您尝试实施的解决方案看起来像是在同一个表上一次又一次地请求,如果它有效,应该比使用 GROUP BY 慢得多。

于 2009-10-08T22:20:21.860 回答