У меня есть таблица меток, которые отображаются в ранжированном порядке.Чтобы гарантировать, что никакие две строки не могут иметь одинаковый ранг, их значения являются уникальными:
create table label (
id_label serial not null,
rank integer not null,
title text not null,
constraint pri primary key (id_label),
constraint unq unique (rank)
)
Не имеет значения, является ли это PostgreSQL или MySQL, они демонстрируют одинаковое поведение.Запрос может выглядеть как select title from label order by rank
.Предположим, что таблица содержит:
id_label rank title
1 10 Cow
2 20 Apple
3 45 Horse
4 60 Beer
Теперь предположим, что я хочу изменить порядок двух меток, например, чтобы Apple ранжировался до Cow.Самый простой способ - поменять их значения ранга:
update label
set rank = case when rank = 20 then 10 else 20 end
where id_label in (1,2)
Нет.Ни:
update label
set rank = case when rank = 20 then rank - 10 else rank + 10 end
where id_label in (1,2)
Ни даже:
update label
set rank = 30 - rank
where id_label in (1,2)
Каждый раз, когда уникальное ограничение срабатывает при обновлении первой строки и прерывает операцию.Если бы я мог отложить проверку до конца заявления, я был бы в порядке.Это происходит как в PostgreSQL, так и в MySQL.
Обходной путь, безопасный для ACID:
- начать транзакцию
- выбрать ранги первой, второй записи и самого высокого (max) ранг в таблице (который, возможно, потребует объединения)
- обновить первую запись в ранг = max + 1
- обновить вторую запись в ранг первой
- обновить в первую очередьзапись в ранг второй
- commit
Это просто невероятно некрасиво.Хуже того, чтобы удалить ограничение, обновить, а затем воссоздать ограничение.Предоставление таких привилегий оперативной роли вызывает проблемы.Итак, мой вопрос заключается в следующем: есть ли простой метод, который я упустил, который решает эту проблему, или я SOL?