Почему это ОБНОВЛЕНИЕ влияет на 2 строки, если его WHERE указывает только одну? - PullRequest
0 голосов
/ 18 июня 2020

Пожалуйста, сравните следующий оператор UPDATE, который я использую в MySQL 8.0, с образцом базы данных Sakila :

UPDATE `film`
SET
    `original_language_id` = FLOOR(1 + (RAND() * 6))
WHERE
    `film_id` = FLOOR(1 + (RAND() * 1000));

Идея состоит в том, чтобы обновить случайную строку из film, чтобы ключ столбца original_language_id для этой строки имел значение от 1 до 6.

В таблице film 1000 строк с PK от 1 до 1000. Столбец original_language_id - это внешний ключ к таблице language. В таблице language 6 строк с PK от 1 до 6.

Вышеупомянутый оператор UPDATE считает небезопасным MySQL (ошибка 1175). (Я бы хотел знать почему, но это не мой вопрос). Итак, чтобы заставить выполнение инструкции выполняться, я предшествую ей: SET SQL_SAFE_UPDATES = 0;.

Когда я затем запускаю инструкцию UPDATE, я ожидаю увидеть в окне вывода:

1 строка (s) Соответствующие затронутые строки: 1 Изменено: 1 Предупреждения: 0

Но вместо этого я иногда получаю 0 затронутых строк, иногда 1, а иногда 2!

Мой вопрос: почему этот оператор UPDATE не влияет на одну и только одну строку?

PS - Пожалуйста, избегайте комментариев о том, имеет ли запрос смысл для вас или нет, и / или о целесообразности отключения безопасный режим обновления. Запрос представляет собой упражнение в учебных целях, и я полностью осознаю важность указанного режима. Спасибо.

Ответы [ 2 ]

4 голосов
/ 18 июня 2020

Предложение WHERE:

WHERE `film_id` = FLOOR(1 + (RAND() * 1000))

выполняется для каждой строки таблицы и каждый раз, когда генерируется случайное число new , которое проверяется на соответствие значению столбца film_id. Так что иногда бывает, что 2 числа равны, это может быть 1,2 или много строк или даже ни одного.

Если вы хотите обновить только 1 случайную строку, вы можете присоединиться к запросу, который возвращает 1 случайное число, например:

UPDATE `film` f
INNER JOIN (SELECT FLOOR(1 + (RAND() * 1000)) rnd) t
ON t.rnd = f.`film_id`
SET `original_language_id` = FLOOR(1 + (RAND() * 6))
2 голосов
/ 18 июня 2020

Если вы хотите выбрать случайную строку для обновления, вы можете просто использовать order by rand() и limit 1:

update film
set original_language_id = floor(1 + (rand() * 6))
order by rand()
limit 1

Это должно быть более эффективным, чем другие решения, использующие соединение - и это работает независимо от количества строк в таблице (в то время как ваш исходный подход требует, чтобы вы заранее знали, сколько строк в таблице)

...