Задавайте вопросы, мы ответим
Вы не зашли.
Страниц: 1
Приветствую, Коллеги!
Есть таблица с некоторыми сущностями, для простоты считаем, что 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 = 0, а потом включить? И делать это все в транзакции?
2) как лучше сделать обновление - через update c case'ом или через on duplicate key или просто состряпать набор похожих апдейтов и пропустить их пачкой, обернув в транзакцию?
У кого есть идеи - поделитесь плиз
Неактивен
Существует ли верхнее ограничение `display_order` ? Чтобы можно было реализовать схему:
1 -> X+1
2 -> 1
X+1 -> 2
Неактивен
В любом случае можно выбрать максимальный существующий display_order и выставить X равный максимальному+1, можно воспользоваться нулём .
Спасибо за идею!, видимо, так и сделаю.
А вариант просто отключить ограничение перед этой серией запросов ты считаешь хуже, да?
Неактивен
Можно использовать временно отрицательные значения. display_order - целое со знаком, но используются только положительные.
(A,B) => (-B, -A) => (B, A)
Неактивен
Это да.. Если там signed ). В общем, как я понял, вариант отключения констрейнта не для этого случая?
Неактивен
На display_order в приведенной структуре таблицы нет слова unsigned, значит signed. Отключение констрейнта - нечто плохое, чего лучше всегда избегать. С максимальным X есть опасность, что в другой транзакции будет добавлена запись с максимальным значением, в результате чего возможен откат одной из транзакций.
Неактивен
Про signed/unsigned я как бы в теории написал. Но так да, дополнительный довод оставить signed . Спасибо.
Неактивен
deadka написал:
В любом случае можно выбрать максимальный существующий display_order и выставить X равный максимальному+1, можно воспользоваться нулём .
Под Х я подразумевал фиксированное большое число про которое заведомо известно, что оно никогда не будет достигнуто, чтобы не возникало пересечений с другими транзакциями. Но тут есть опасность, что в будущем ситуация изменится, и тогда возникнут проблемы. Вариант с отрицательными числами гораздо лучше.
deadka написал:
А вариант просто отключить ограничение перед этой серией запросов ты считаешь хуже, да?
1. Не известно, где используется эта уникальность и не возникнет ли ошибка в другой части приложения из-за временного отключения.
2. Имхо, это как-то идеологически неверно.
Неактивен
Страниц: 1