У меня есть ситуация, когда мне нужно применить уникальное ограничение для набора столбцов, но только для одного значения столбца.
Так, например, у меня есть таблица типа Table (ID, Name, RecordStatus).
RecordStatus может иметь только значение 1 или 2 (активен или удален), и я хочу создать уникальное ограничение для (ID, RecordStatus) только тогда, когда RecordStatus = 1, поскольку мне все равно, есть ли несколько удаленных записей с одинаковыми МНЕ БЫ.
Могу ли я это сделать, помимо написания триггеров?
Я использую SQL Server 2005.
sql
sql-server
sql-server-2005
нп-жесткий
источник
источник
Ответы:
Добавьте такое ограничение проверки. Разница в том, что вы вернете false, если Status = 1 и Count> 0.
http://msdn.microsoft.com/en-us/library/ms188258.aspx
CREATE TABLE CheckConstraint ( Id TINYINT, Name VARCHAR(50), RecordStatus TINYINT ) GO CREATE FUNCTION CheckActiveCount( @Id INT ) RETURNS INT AS BEGIN DECLARE @ret INT; SELECT @ret = COUNT(*) FROM CheckConstraint WHERE Id = @Id AND RecordStatus = 1; RETURN @ret; END; GO ALTER TABLE CheckConstraint ADD CONSTRAINT CheckActiveCountConstraint CHECK (NOT (dbo.CheckActiveCount(Id) > 1 AND RecordStatus = 1)); INSERT INTO CheckConstraint VALUES (1, 'No Problems', 2); INSERT INTO CheckConstraint VALUES (1, 'No Problems', 2); INSERT INTO CheckConstraint VALUES (1, 'No Problems', 2); INSERT INTO CheckConstraint VALUES (1, 'No Problems', 1); INSERT INTO CheckConstraint VALUES (2, 'Oh no!', 1); INSERT INTO CheckConstraint VALUES (2, 'Oh no!', 2); -- Msg 547, Level 16, State 0, Line 14 -- The INSERT statement conflicted with the CHECK constraint "CheckActiveCountConstraint". The conflict occurred in database "TestSchema", table "dbo.CheckConstraint". INSERT INTO CheckConstraint VALUES (2, 'Oh no!', 1); SELECT * FROM CheckConstraint; -- Id Name RecordStatus -- ---- ------------ ------------ -- 1 No Problems 2 -- 1 No Problems 2 -- 1 No Problems 2 -- 1 No Problems 1 -- 2 Oh no! 1 -- 2 Oh no! 2 ALTER TABLE CheckConstraint DROP CONSTRAINT CheckActiveCountConstraint; DROP FUNCTION CheckActiveCount; DROP TABLE CheckConstraint;
источник
Вот отфильтрованный индекс . Из документации (выделено мной):
А вот пример объединения уникального индекса с предикатом фильтра:
create unique index MyIndex on MyTable(ID) where RecordStatus = 1;
По сути, это обеспечивает уникальность того,
ID
когдаRecordStatus
есть1
.После создания этого индекса нарушение уникальности вызовет ошибку:
Примечание: отфильтрованный индекс был введен в SQL Server 2008. Для более ранних версий SQL Server см. Этот ответ .
источник
ansi_padding
отфильтрованных индексов, поэтому убедитесь, что эта опция включена, выполнивSET ANSI_PADDING ON
перед созданием отфильтрованного индекса.Вы можете переместить удаленные записи в таблицу, в которой отсутствует ограничение, и, возможно, использовать представление с UNION двух таблиц, чтобы сохранить внешний вид одной таблицы.
источник
Вы можете сделать это по-настоящему хакерским способом ...
Создайте для своей таблицы представление, связанное со схемой.
СОЗДАТЬ ВИД Независимо от того, что ВЫБРАТЬ * ИЗ таблицы, ГДЕ RecordStatus = 1
Теперь создайте уникальное ограничение для представления с нужными полями.
Одно замечание о представлениях, связанных со схемой: если вы измените базовые таблицы, вам придется воссоздать представление. Из-за этого много подводных камней.
источник
Поскольку вы собираетесь разрешить дублирование, уникальное ограничение не сработает. Вы можете создать проверочное ограничение для столбца RecordStatus и хранимую процедуру для INSERT, которая проверяет существующие активные записи перед вставкой повторяющихся идентификаторов.
источник
Если вы не можете использовать NULL в качестве RecordStatus, как предлагал Билл, вы можете объединить его идею с индексом на основе функций. Создайте функцию, которая возвращает NULL, если RecordStatus не является одним из значений, которые вы хотите учитывать в своем ограничении (и RecordStatus в противном случае), и создайте индекс над этим.
Это будет иметь то преимущество, что вам не придется явно проверять другие строки в таблице в вашем ограничении, что может вызвать проблемы с производительностью.
Я должен сказать, что вообще не знаю SQL-сервер, но я успешно использовал этот подход в Oracle.
источник