SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 24.02.2014 23:49:02

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

update нескольких рядов в одной таблице с разными условиями

Приветствую, Коллеги!

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

CREATE TABLE `t` (
    `id` int unsigned NOT NULL auto_increment,
    `display_order` int(11) NOT NULL,
    CONSTRAINT `t__display_order__unique` UNIQUE(`display_order`),
    CONSTRAINT `t__pk` PRIMARY KEY(`id`)
) engine=innodb default charset=utf8;
INSERT INTO `t`(`display_order`) VALUES(1),(2),(3);
 


Пробую так:
UPDATE `t` SET display_order = CASE id WHEN 1 THEN 2 WHEN 2 THEN 1 END WHERE id IN (1,2);
получаю в ответ
ERROR 1062 (23000): Duplicate entry '2' for key 't__display_order__unique'

То есть значения меняются не одновременно (хотя это и происходит в рамках одного запроса), и срабатывает ограничение уникальности на display_order.

Попытка сделать insert с on duplicate update даёт также ошибку.

Отказываться от ограничения уникальности на display_order не хочется, оно не для украшения..

Возникают вопросы - как лучше решить эту задачу?
1) Отключить перед запросом вторичные ключи (SET FOREIGN_KEY_CHECKS = 0wink, а потом включить? И делать это все в транзакции?
2) как лучше сделать обновление - через update c case'ом или через on duplicate key или просто состряпать набор похожих апдейтов и пропустить их пачкой, обернув в транзакцию?

У кого есть идеи - поделитесь плиз smile


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#2 25.02.2014 03:34:09

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: update нескольких рядов в одной таблице с разными условиями

Существует ли верхнее ограничение `display_order` ? Чтобы можно было реализовать схему:
1 -> X+1
2 -> 1
X+1 -> 2

Неактивен

 

#3 25.02.2014 09:43:03

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: update нескольких рядов в одной таблице с разными условиями

В любом случае можно выбрать максимальный существующий display_order и выставить X равный максимальному+1, можно воспользоваться нулём smile.
Спасибо за идею!, видимо, так и сделаю.
А вариант просто отключить ограничение перед этой серией запросов ты считаешь хуже, да?


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#4 25.02.2014 12:07:26

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: update нескольких рядов в одной таблице с разными условиями

Можно использовать временно отрицательные значения. display_order - целое со знаком, но используются только положительные.
(A,B) => (-B, -A) => (B, A)

Неактивен

 

#5 25.02.2014 12:09:47

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: update нескольких рядов в одной таблице с разными условиями

Это да.. Если там signed ). В общем, как я понял, вариант отключения констрейнта не для этого случая?


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#6 25.02.2014 12:16:58

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: update нескольких рядов в одной таблице с разными условиями

На display_order в приведенной структуре таблицы нет слова unsigned, значит signed. Отключение констрейнта - нечто плохое, чего лучше всегда избегать. С максимальным X есть опасность, что в другой транзакции будет добавлена запись с максимальным значением, в результате чего возможен откат одной из транзакций.

Неактивен

 

#7 25.02.2014 12:26:31

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2422

Re: update нескольких рядов в одной таблице с разными условиями

Про signed/unsigned я как бы в теории написал. Но так да, дополнительный довод оставить signed smile. Спасибо.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#8 25.02.2014 15:03:23

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: update нескольких рядов в одной таблице с разными условиями

deadka написал:

В любом случае можно выбрать максимальный существующий display_order и выставить X равный максимальному+1, можно воспользоваться нулём smile.

Под Х я подразумевал фиксированное большое число про которое заведомо известно, что оно никогда не будет достигнуто, чтобы не возникало пересечений с другими транзакциями. Но тут есть опасность, что в будущем ситуация изменится, и тогда возникнут проблемы. Вариант с отрицательными числами гораздо лучше.

deadka написал:

А вариант просто отключить ограничение перед этой серией запросов ты считаешь хуже, да?

1. Не известно, где используется эта уникальность и не возникнет ли ошибка в другой части приложения из-за временного отключения.
2. Имхо, это как-то идеологически неверно.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson