0

Пусть существует таблица users с полями user_id и user_name, и в ней имеются записи с одниковыми значениями user_name. Запрос удаления "лишних" строк будет выглядеть, допустим, так:

DELETE FROM users WHERE user_id IN
  (SELECT user_id FROM users WHERE user_name IN
    (SELECT user_name FROM
      (SELECT user_id, COUNT(*) AS cnt, user_name FROM users GROUP BY user_name HAVING cnt>1) AS t1
    )
  AND user_id NOT IN (SELECT user_id FROM users GROUP BY user_name)
  )

Или так:

DELETE FROM users WHERE user_id IN
  (SELECT t1.user_id FROM
    (SELECT user_id, user_name FROM users) AS t1
  INNER JOIN
    (SELECT user_name, COUNT(*) AS cnt, MIN(user_id) AS min_id FROM users GROUP BY user_name HAVING cnt > 1) AS t2
  ON t1.user_name=t2.user_name AND t1.user_id!=t2.min_id
  )

В общем, как ни крути, получается, по сути, два вложенных селекта, и время работы, по идее, соответственно, в два раза больше, хотя если бы можно было обратиться к результату t1 после AND в первом примере, то было бы более по фэншую, наверно (а так костыли какие-то). Можно ли как-то это исправить?

И второе, почему-то на указанные выше примеры SQLyog ругается:

Error Code: 1093
You can't specify target table 'users' for update in FROM clause

Английский у меня хромает, но, насколько я понял, оно утверждает, что я не могу отправить в команду удаления результат вложенного запроса!? О_о

P.S. Сильно не ругайте, sql не вспоминал ещё со школьных лет...

2
  • 1
    > И второе, почему-то на указанные выше примеры SQLyog ругается: не SQLyog, а сам MySQL. Запросы на обновление данных, включающие подзапросы, работающие с обновляемой таблицей, запрещены. В принципе, можно обмануть MySQL и сделать еще один промежуточный селект-обертку.
    – etki
    26 авг 2014 в 20:06
  • hashcode.ru/questions/193369/… 26 авг 2014 в 21:01

2 ответа 2

0

В надежде, что user_id - первичный ключ:

delete from users where user_id not in(
select max(user_id) from users 
group by user_name);

Это классика. user_id в запросе можно заменить на rowid, если такая псевдоколонка существует в вашей СУБД.

6
  • Читайте комментарии, если проверять лень. > Запросы на обновление данных, включающие подзапросы, работающие с обновляемой таблицей, запрещены. 27 авг 2014 в 12:40
  • @Yura Ivanov, я таким запросом пользовался многократно.
    – BuilderC
    27 авг 2014 в 14:30
  • MySQL? sqlfiddle.com/#!2/04e35 > You can't specify target table 'users' for update in FROM clause: 27 авг 2014 в 14:39
  • ссылка на схему с ошибкой не создается. sqlfiddle.com/#!2/4338fb раскомментировать надо запрос. 27 авг 2014 в 14:41
  • @Yura Ivanov,нет, не MySQL, а Oracle.
    – BuilderC
    27 авг 2014 в 15:49
0

Всем спасибо за помощь. Хоть после комментариев это стало и очевидно, на всякий случай напишу здесь работающий с mysql код (с упомянутой селект-обёрткой), может, кому и пригодится:

DELETE FROM users WHERE user_id NOT IN (
    SELECT * FROM
        (SELECT MAX(user_id) FROM users GROUP BY user_name) AS t1
)

Ваш ответ

By clicking “Отправить ответ”, you agree to our terms of service and acknowledge you have read our privacy policy.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками или задайте свой вопрос.