Обновление записей базы данных с уникальным ограничением

Учитывая следующую простую структуру таблицы (SQL Server 2008), я хочу иметь возможность поддерживать уникальность моего столбца числовой последовательности, но я хочу иметь возможность обновлять это значение для любой заданной записи (записей).

CREATE TABLE MYLIST(
      ID int NOT NULL IDENTITY(1, 1)
    , TITLE varchar(50) NOT NULL
    , SEQUENCE int NOT NULL
    , CONSTRAINT pk_mylist_id PRIMARY KEY(ID)
    , CONSTRAINT uq_mylist_sequence UNIQUE(SEQUENCE)
);

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

Например, скажем, у меня есть эти записи:

ID  TITLE   SEQUENCE
1   APPLE   1
2   BANANA  2
3   CHERRY  3

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

ID  TITLE   SEQUENCE
1   APPLE   3
2   BANANA  1
3   CHERRY  2

Но на самом деле я мог бы иметь дело с парой десятков предметов. Порядковые номера не должны пересекаться. Я думал о том, чтобы попытаться использовать триггеры или временно отключить ограничение, но это, похоже, создаст больше проблем. Я использую C# и LINQ-to-SQL, но открыт исключительно для баз данных.


person JustinStolle    schedule 25.01.2011    source источник
comment
Можете ли вы обновить в одном заявлении?   -  person gbn    schedule 25.01.2011
comment
У меня есть свобода попробовать что угодно, если это ответит на ваш вопрос.   -  person JustinStolle    schedule 25.01.2011


Ответы (3)


Вы можете присвоить им отрицательное их правильное значение, а затем, после того, как все обновления произошли, выполните окончательное обновление, где вы установите SEQUENCE = -SEQUENCE.

Это не очень эффективно, но поскольку вы говорите, что у вас всего пара десятков элементов, я сомневаюсь, что эффект будет заметным. Я также предполагаю, что вы можете использовать отрицательные числа в качестве «магических значений» для обозначения временно неверно назначенных значений.

person Dave Mateer    schedule 25.01.2011
comment
Мне нравится простота этого, и я сам подумал об этом через несколько минут после публикации вопроса. Для моей ситуации это может иметь наибольший смысл. - person JustinStolle; 25.01.2011
comment
Хм... ничто не мешает кому-то ввести отрицательное число прямо в базу данных, что нарушит это решение. - person XåpplI'-I0llwlg'I -; 06.01.2014

Очевидный способ - написать как одну партию. Внутри SQL откладывает проверки ограничений, поэтому промежуточная уникальность не имеет значения.

Писать построчно не имеет смысла и вызывает проблему, которая у вас есть.

Вы можете изменить это, чтобы записать во временную таблицу, а затем «сбросить» результаты в конце, даже сначала проверить уникальность временной таблицы.

DECLARE @NewSeq TABLE (ID int, NewSeq int)

INSERT @NewSeq (ID, NewSeq) VALUES (1, 3)
INSERT @NewSeq (ID, NewSeq) VALUES (2, 1)
INSERT @NewSeq (ID, NewSeq) VALUES (3, 2)

UPDATE
   M
SET
   SEQUENCE = NewSeq
FROM
   MYLIST M
   JOIN
   @NewSeq N ON M.ID = N.ID
person gbn    schedule 25.01.2011
comment
Это кажется технически правильным решением с наименьшей вероятностью ошибки, хотя для этого потребуется дополнительный код. Для моих целей достаточно трюка Дэйва с отрицательными числами. - person JustinStolle; 26.01.2011

Если вам действительно нужно следовать этому рабочему процессу вставки, не зная правильного порядка, а затем возвращаться с обновлением позже, чтобы установить правильный порядок, я бы сказал, что ваш лучший вариант - избавиться от уникального ограничения, потому что оно вызывает у вас больше проблем, чем оно того стоит. Конечно, только вы знаете, сколько это уникальное ограничение «стоит» для вашего приложения.

person Russell McClure    schedule 25.01.2011
comment
Я знаю правильный/желаемый порядок заранее до обновления. - person JustinStolle; 26.01.2011
comment
Верно, но вы не знаете правильный порядок перед вставкой, верно? - person Russell McClure; 26.01.2011
comment
Я бы знал как текущую последовательность, так и желаемую новую последовательность для всех записей. Я спрашиваю только об обновлениях, а не о вставках. Но мне любопытно, ваша интерпретация уникальных ограничений заключается в том, что их значения могут быть записаны только один раз и никогда не изменятся? - person JustinStolle; 26.01.2011
comment
Нет. Я просто пытался уточнить, что вы не знаете правильных значений до того, как записи будут вставлены в первый раз. Таким образом, они должны быть вставлены с неправильными значениями, а позже вы должны вернуться и выполнить обновление. - person Russell McClure; 26.01.2011
comment
Я не уверен, почему вы спрашиваете о вставке, поскольку это выходит за рамки моего вопроса, но ради аргумента я бы вставил новые записи в конец существующей последовательности (например, MAX(SEQUENCE)+1). Если пользователь не хочет этого в конце, он может переместить его, и я вернусь к исходному вопросу. - person JustinStolle; 26.01.2011