Обновление с помощью SELECT и группы без GROUP BY - PullRequest
0 голосов
/ 09 октября 2009

У меня есть такая таблица (MySQL 5.0.x, MyISAM):

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

Я хотел бы обновить статус с нового (status=1) до нескольких (status=3) всех ответов, если хотя бы 20 имеют одинаковый заголовок.

У меня есть этот, но он не работает:

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 ]

1 голос
/ 09 октября 2009

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.

0 голосов
/ 09 октября 2009

Я бы написал что-нибудь простое, как показано ниже

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, если оно работает.

0 голосов
/ 09 октября 2009

вам придется использовать временную таблицу:

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;
0 голосов
/ 09 октября 2009

Это забавная особенность MySQL - я не могу придумать, как это сделать одним оператором (GROUP BY или нет GROUP BY).

Вы можете сначала выбрать соответствующие строки ответов во временной таблице, а затем выполнить обновление, выбрав из этой временной таблицы.

...