Атомарное многострочное обновление с уникальным ограничением

У меня есть таблица меток, которые отображаются в ранжированном порядке. Чтобы гарантировать, что никакие две строки не могут иметь одинаковый ранг, их значения уникальны:

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, они демонстрируют одинаковое поведение. Запрос может выглядеть так: выберите заголовок из порядка ярлыков по рангу . Предположим, что таблица содержит:

id_label rank title
1        10   Cow
2        20   Apple
3        45   Horse
4        60   Beer

Теперь предположим, что я хочу переупорядочить две метки, например, поставить Apple выше коровы. Самый простой способ - поменять местами их значения ранга:

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 обходной путь:

  1. начать транзакцию
  2. выбрать ранги первой, второй записи и наивысшего (максимального) ранга в таблице (что, вероятно, потребует union)
  3. обновить первую запись до ранга = max + 1
  4. обновить вторую запись до ранга первой
  5. обновить первую запись до ранга второй
  6. фиксации

Это просто невыразимо уродливо. Хуже того, нужно отбросить ограничение, обновить, а затем воссоздать ограничение. Предоставление таких привилегий оперативной роли вызывает проблемы. Итак, мой вопрос: есть ли простой метод, который я упустил из виду, который решает эту проблему, или я - СОЛНЕЧНЫЙ?

12
задан Juan Mellado 1 May 2012 в 18:31
поделиться