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.