2016-08-01 5 views
0

У меня есть объект Sequence, установленный в одной из наших баз данных с шагом 1, который мы в настоящее время используем в качестве первичного ключа для двух наших таблиц, чтобы обеспечить уникальность через них обоих. Это контролируется с помощью следующих ограничений на столах:SQL Server: предотвращение ручного ввода в колонку, управляемую последовательностью

ADD CONSTRAINT SEQ_MySequence DEFAULT (NEXT VALUE FOR dbo.SEQ_sID) FOR ID; 

Мы хотим запретить пользователю вручную вставлять данные в эту колонку, но мы не можем найти надежный способ сделать это. Триггер кажется очевидным выбором; однако после INSERT триггеры выполняются после ограничения обжигают и, таким образом, ниже не работает:

CREATE TRIGGER BlockInsert ON MyTable 
AFTER INSERT 
AS 
    IF (SELECT ID FROM inserted) IS NOT NULL 
    BEGIN 
     ROLLBACK 
END 

Кто-нибудь есть какие-нибудь идеи?

+0

Вы гуглом других типов триггеров? – dfundako

+0

Удалите разрешения на вставку в таблицу и убедитесь, что все вставки и обновления должны проходить через представление, не отображающее этот столбец? –

+0

Вместо этого вы можете использовать столбец «Identity»? –

ответ

2

Если основная цель последовательности состоит только в том, чтобы обеспечить уникальность между двумя таблицами, рассмотрите возможность использования нечетных и четных столбцов в таблицах. Пример Таблица A будет иметь семенной идентификатор 1 с шагом 2 (нечетный), а таблица B будет иметь семестр идентичности 2 с шагом 2 (четный). Если есть вероятность, что IDENTITY_INSERT может быть использован, вам также нужно будет добавить дополнительные контрольные ограничения для обеспечения правильного поведения. Пример использования:

CREATE TABLE TableA 
(
    ID int NOT NULL IDENTITY (1 , 2) CONSTRAINT PK_Odd PRIMARY KEY CLUSTERED , 
    Data varchar(10) 
) 

-- Check constraint ensures ID is always odd 
ALTER TABLE TableA ADD CONSTRAINT 
CK_ODD_ID CHECK (ID % 2 = 1) 


CREATE TABLE TableB 
(
    ID int NOT NULL IDENTITY (2 , 2) CONSTRAINT PK_Even PRIMARY KEY CLUSTERED , 
    Data varchar(10) 
) 
-- Check constraint ensures ID is always even 
ALTER TABLE TableB ADD CONSTRAINT 
CK_EVEN_ID CHECK (ID % 2 = 0) 

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

+0

Это отличное предложение. Если в будущем потребуется больше таблиц, то идентификаторы могут быть изменены с помощью столбца alter. Например. 'ALTER TABLE TableA ALTER COLUMN ID INT NOT NULL IDENTITY (10001, 4)' и 'ALTER TABLE TableA ALTER COLUMN ID INT NOT NULL IDENTITY (10002, 4)' и т. Д. – Ben

+0

@Ben - За исключением такого синтаксиса.Единственный способ сделать это как изменение только метаданных - это «ALTER TABLE .. SWITCH» –

+0

Простое и инновационное решение. Однако мы можем захотеть, чтобы это значение было уникальным по сравнению с третьей таблицей в будущем, и, как вы указали в нижней части вашего ответа, этот метод не будет работать. Однако большое спасибо за ваш вклад! – SeeBeeEss

1

Спасибо за все ваши предложения. Я придумал решение ниже используя INSTEAD OF INSERT триггера, который я чувствую имитирует поведение столбца идентификации достаточно хорошо:

CREATE TRIGGER BlockInsert ON MyTable 
INSTEAD OF INSERT 
AS 
    IF (SELECT ID FROM inserted) IS NOT NULL 
     THROW 50000, 'Explict insert into column "ID" is forbidden', 1 
    ELSE 
     INSERT INTO MyTable ([ID],[ColumnA],[ColumnB]) 
     SELECT NEXT VALUE FOR dbo.MySequenceObject,[ColumnA],[ColumnB] 
     FROM inserted 
END 

Это проверяет, если значение ID пользователь пытается вставить это фактическое значение вместо из NULL. Если это так, вставка прерывается и возникает ошибка. Если нет, строка вставляется с использованием следующего значения Sequence в качестве столбца ID.

Поскольку INSTEAD OF Триггеры встречаются перед любыми ограничениями таблицы, это не нарушает ограничение NOT NULL столбца, а также происходит до того, как строка, которую нужно вставить, получит идентификатор из последовательности.

Таким образом, пользователь никогда не сможет вставить свое собственное значение в столбец идентификатора - он должен поступать из объекта последовательности - это то, что мы хотим.

Обновление также может быть обработано с помощью ниже триггера:

CREATE TRIGGER BlockUpdate ON MyTable 
AFTER UPDATE 
AS 
    IF UPDATE ([ID]) 
     THROW 50000, 'Update of column "ID" is forbidden', 1 
     ROLLBACK 
END