Как ссылаться на другие таблицы в ограничениях check?


У меня есть таблица, ProductSupportArticles:

ProductSupportArticleID int NOT NULL <primary key>
ParentArticleID int NULL
ProductID int NOT NULL
Title varchar(100) NOT NULL
Content varchar(MAX) NOT NULL

"Кодтовара" является внешним ключом для продуктов.Идентификатор ParentArticleID является внешним ключом в таблице, ProductSupportArticles.ProductSupportArticleID. У меня есть ограничение проверки ProductSupportArticleID != ParentArticleID, чтобы статья не могла быть собственным родителем.

Однако вспомогательная статья, относящаяся к конкретному продукту, не должна быть родителем или дочерним элементом статьи, относящейся к другому продукту. Как можно Я добавляю ограничение проверки или аналогичное высказывание: (ProductID = (SELECT ProductID FROM ProductSupportArticles P WHERE ParentArticleID = P.ProductSupportArticleID))

Или как я должен реализовать свои таблицы по-другому?

2 5

2 ответа:

  1. Создайте уникальное ограничение на (ProductSupportArticleID, ProductID).
  2. Есть FK refer (ParentArticleID, ProductID) to (ProductSupportArticleID, ProductID)

Предупреждение: применение бизнес-правил с помощью UDFs, обернутых в ограничения CHECK, имеет множество лазеек. Например, они могут давать ложные положительные и ложные отрицательные значения для многорядных модификаций. Кроме того, они очень медлительны.

Рабочий образец

Примеры таблиц:

create table products (productid int primary key)
insert products select 1
insert products select 2
GO

create table ProductSupportArticles (
ProductSupportArticleID int NOT NULL primary key,
ParentArticleID int NULL references ProductSupportArticles(ProductSupportArticleID),
ProductID int NOT NULL references products (productid),
Title varchar(100) NOT NULL,
Content varchar(MAX) NOT NULL
)
GO

Функция поддержки

create function dbo.getProductSupportArticleParent(@ParentArticleID int)
returns int
with returns null on null input
as
begin
return (select ProductID from ProductSupportArticles where ProductSupportArticleID = @ParentArticleID)
end
GO

Ограничение

alter table ProductSupportArticles add check(
    ParentArticleID is null or
    dbo.getProductSupportArticleParent(ParentArticleID) = ProductID)
GO

Тесты

insert ProductSupportArticles select 1,null,1,3,4
insert ProductSupportArticles select 2,null,1,3,4
insert ProductSupportArticles select 3,null,2,3,4
insert ProductSupportArticles select 4,1,1,3,4

Хорошо, пока этот следующий нарушает его, потому что 5 является родительским 1, который принадлежит продукту 1.

insert ProductSupportArticles select 5,1,2,3,4


EDIT

Алекс указал на действительный недостаток. Чтобы охватить этот сценарий, вам потребуется триггер обновления, который распространит изменения ProductID записи на все дочерние (и потомственные) записи. Это было бы будьте простым триггером, поэтому я не буду предоставлять код здесь.