mysql удалить в безопасном режиме


87

У меня есть инструктор по таблицам, и я хочу удалить записи с диапазоном зарплаты. Интуитивно понятный способ выглядит так:

delete from instructor where salary between 13000 and 15000;

Однако в безопасном режиме я не могу удалить запись, не предоставив первичный ключ (ID).

Итак, я пишу следующий sql:

delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

Однако есть ошибка:

You can't specify target table 'instructor' for update in FROM clause

Я запутался, потому что когда я пишу

select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

это не вызывает ошибки.

У меня вопрос:

  1. что на самом деле означает это сообщение об ошибке и почему мой код неверен?
  2. как переписать этот код, чтобы он работал в безопасном режиме?

Благодарность!


вы хотели оставить безопасный режим включенным? и вы используете рабочую среду mySql?
— запись

ответ на оба ваших вопроса - да. И я удивлен, что когда я использовал jdbc для удаления записей в базах данных mysql без PK, это не вызывает ошибки. Итак, безопасный режим предназначен только для верстака mysql?
— Роланд Луо

1
нет - я спрашивал, потому что, если бы вы хотели выключить его в рабочей среде mySQL, я мог бы сказать вам, как это сделать. Лично я работаю с этим выключенным ... наличие идентификаторов - это большая безопасность с точки зрения безопасности, но с точки зрения разработки я обнаружил, что это
— проблема

Ответы:


226

Погуглив, популярный ответ, кажется, "просто выключи безопасный режим" :

SET SQL_SAFE_UPDATES = 0;
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;
SET SQL_SAFE_UPDATES = 1;

Если честно, я не могу сказать, что когда-либо имел привычку бегать в безопасном режиме. Тем не менее, мне не совсем удобен этот ответ, поскольку он просто предполагает, что вы должны менять конфигурацию своей базы данных каждый раз, когда сталкиваетесь с проблемой.

Итак, ваш второй запрос ближе к цели, но сталкивается с другой проблемой: MySQL применяет несколько ограничений к подзапросам, и одно из них заключается в том, что вы не можете изменять таблицу, выбирая из нее в подзапросе.

Цитата из руководства MySQL, Ограничения на подзапросы :

Как правило, вы не можете изменять таблицу и выбирать из той же таблицы в подзапросе. Например, это ограничение применяется к операторам следующих форм:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Исключение: предыдущий запрет не применяется, если вы используете подзапрос для измененной таблицы в предложении FROM. Пример:

UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

Здесь результат подзапроса в предложении FROM сохраняется как временная таблица, поэтому соответствующие строки в t уже были выбраны к моменту обновления t.

Последнее - ваш ответ. Выберите целевые идентификаторы во временной таблице, затем удалите их, указав идентификаторы в этой таблице:

DELETE FROM instructor WHERE id IN (
  SELECT temp.id FROM (
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
  ) AS temp
);

Демонстрация SQLFiddle .


6
Спасибо за объяснение! Однако я попробовал ваш код в mysql workbench, и он по-прежнему сказал: «Вы используете режим безопасного обновления, и вы пытались обновить таблицу без WHERE, которая использует столбец KEY».
— Роланд Луо

Это неожиданно. Ваш первичный ключ под другим именем? Я заметил, что ваш вопрос, кажется, указывает, что он назван ID, в то время как в моем ответе используется id.
— rutter

Да, я меняю его на ID, и он не работает. Я попытался удалить из инструктора, где ID = '1', и он работает, поэтому ID является первичным ключом
— Роланд Луо

1
@rolandluo Я знаю, что это было давно, но мне любопытно, придумали ли вы когда-нибудь обходной путь. Ясно, что этот метод работал в других обстоятельствах, поэтому мне интересно, почему ваш случай отличается. Возможно, что-то специфическое для вашего сервера или версии?
— rutter

19

Вы можете обмануть MySQL, заставив думать, что вы на самом деле указываете столбец первичного ключа. Это позволяет вам «переопределить» безопасный режим.

Предполагая, что у вас есть таблица с автоматически увеличивающимся числовым первичным ключом, вы можете сделать следующее:

DELETE FROM tbl WHERE id <> 0

12

Отключение безопасного режима в Mysql Workbench 6.3.4.0

Меню Правка => Настройки => Редактор SQL: Другой раздел: нажмите «Безопасные обновления» ..., чтобы снять флажок

Настройки Workbench


2
"как переписать этот код, чтобы он работал в безопасном режиме ?" ==> В вашем ответе рассказывается, как отключить безопасный режим;)
— ByteHamster 02

2
Извините, я совершенно не понял вопрос. Я нашел эту тему, когда мне не удалось удалить из таблиц с помощью рабочей среды Mysql, и в комментарии к рабочей среде mysql был аналогичный вопрос, но я не могу создавать комментарии. Я подумал, что это хорошее место, чтобы написать это здесь для дальнейшего использования ...
— Питер Би

0

У меня есть гораздо более простое решение, оно работает для меня; это также обходной путь, но его можно использовать, и вам не нужно менять настройки. Я предполагаю, что вы можете использовать значение, которого никогда не будет, затем вы используете его в своем предложении WHERE

УДАЛИТЬ ИЗ MyTable, ГДЕ MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Мне тоже не очень нравится это решение, поэтому я здесь, но оно работает и кажется лучше, чем то, что на него ответили.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.