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でSELECTFROMUPDATEターゲットを実行することができます。ここで解決策を参照してください
  • 問題は、選択されたデータにありますが、これは完全に間違っています。
  • 私が見つけた唯一の解決策は、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

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 BYMySQLでは一時的なテーブルが発生することが多く、これにはコストがかかる可能性があることを理解しています。しかし、それは契約破りですか?このクエリを実行する必要がある頻度はどれくらいですか。さらに、他のソリューションでも一時テーブルが必要になる可能性があります。


私はこの問題を使用せずに解決する1つの方法を考えることができます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の面白い特徴です-単一のステートメント(GROUPBYまたはGROUPBYなし)でそれを行う方法を考えることはできません。

最初に一時テーブルに適切な応答行を選択してから、その一時テーブルから選択して更新を行うことができます。

于 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の使用は本当に遅いですか?実装しようとしたソリューションは、同じテーブルで何度もリクエストするように見え、それが機能する場合はGROUPBYを使用するよりもはるかに遅くなるはずです。

于 2009-10-08T22:20:21.860 に答える