Как установить проверку целостности базы данных для полей, на которые ссылаются внешние ключи - PullRequest
0 голосов
/ 26 марта 2011

У меня есть четыре таблицы базы данных, подобные этим:

Книга
ID_Book | ID_Company | Описание

BookExtension
ID_BookExtension |ID_Book |ID_Discount

Скидка
ID_Discount |Описание |ID_Company

Компания
ID_Company |Описание

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

BookExtension.ID_Book ссылается на запись Book, которая содержит Book.ID_Company
BookExtension.ID_Discount ссылается на запись Discount, которая содержит Discount.ID_Company

Возможно ли принудительно установить в Sql Server, что любая новая запись в BookExtension должна иметь Book.ID_Company = Discount.ID_Company?

Короче говоря, я хочу, чтобы следующий запрос возвращал 0 записей!

SELECT count(*) from BookExtension 
INNER JOIN Book ON BookExstension.ID_Book = Book.ID_Book
INNER JOIN Discount ON BookExstension.ID_Discount = Discount.ID_Discount
WHERE Book.ID_Company <> Discount.ID_Company

или, простым языком:
Я не хочу, чтобы запись BookExtension ссылалась на Book запись Company и Discount запись другой другой Company!

Ответы [ 2 ]

2 голосов
/ 27 марта 2011

Я не уверен, насколько это [in] эффективно, но вы также можете использовать индексированное представление для достижения этой цели.Требуется вспомогательная таблица с 2 строками, поскольку CTE и UNION недопустимы в индексированных представлениях.

CREATE TABLE dbo.TwoNums
 (
 Num int primary key
 )

 INSERT INTO TwoNums SELECT 1 UNION ALL SELECT 2

Затем определение представления

 CREATE VIEW dbo.ConstraintView
 WITH SCHEMABINDING
 AS
    SELECT 1 AS Col FROM dbo.BookExtension 
    INNER JOIN dbo.Book ON dbo.BookExtension.ID_Book = Book.ID_Book
    INNER JOIN dbo.Discount ON dbo.BookExtension.ID_Discount = Discount.ID_Discount
    INNER JOIN dbo.TwoNums ON  Num = Num
    WHERE dbo.Book.ID_Company <> dbo.Discount.ID_Company

И уникальный индекс в представлении

CREATE UNIQUE CLUSTERED INDEX [uix] ON [dbo].[ConstraintView]([Col] ASC)   
2 голосов
/ 26 марта 2011

Если я не понял вашего намерения, общая форма оператора SQL, который вы будете использовать, будет

ALTER TABLE FooExtension
ADD CONSTRAINT your-constraint-name
CHECK (ID_Foo = ID_Bar);

Это предполагает, что существующие данные уже соответствуют новому ограничению. Если существующие данные не соответствуют, вы можете либо исправить данные (при условии, что они нуждаются в исправлении), либо вы можете ограничить область действия (возможно) нового ограничения, также проверив значение ID_FooExtension. (Предполагая, что вы можете определить «новые» строки по значению ID_FooExtension.)

Позже. , .

Спасибо, я действительно неправильно понял вашу ситуацию.

Насколько я знаю, вы не можете применить это ограничение так, как вы хотите в SQL Server, потому что он не разрешает запросы SELECT в ограничении CHECK. (Я могу ошибаться в SQL Server 2008). Обычный обходной путь заключается в том, чтобы обернуть запрос SELECT в функцию и вызвать функцию, но, как я понял, это ненадежно.

Вы можете сделать это, хотя.

  1. Создать УНИКАЛЬНОЕ ограничение для Книги (ID_Book, ID_Company). Часть этого будет выглядеть как UNIQUE (ID_Book, ID_Company).
  2. Создание уникального ограничения на скидку (ID_Discount, ID_Company).
  3. Добавить две колонки в BookExtension - Book_ID_Company и Discount_ID_Company.
  4. Заполните эти новые столбцы.
  5. Изменить ограничения внешнего ключа в BookExtension. Ты хочешь BookExtension (ID_Book, Book_ID_Company) для ссылки Книга (ID_Book, ID_Company). Аналогичное изменение для внешнего ключа
    ссылка на скидку.

Теперь вы можете добавить проверочное ограничение, чтобы гарантировать, что BookExtension.Book_ID_Company совпадает с BookExtension.Discount_ID_Company.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...