Поддержание целостности данных в циклических ссылках в SQL Server 2012

Допустим, у нас есть три таблицы Customer, City и Country.

Таблица страны:

  • ID(PK)
  • Имя.

Таблица города:

  • ID (PK)
  • CountryID (ФК)
  • Имя

Таблица клиентов:

  • ID(PK)
  • CountryID(FK)(NULL)
  • CityID(FK)(NULL)
  • Имя и тд...

Как вы можете догадаться, Заказчик мог назначить или не назначить CityID или CountryID.

Итак, как лучше всего гарантировать, что при вставке/обновлении клиента мы не получим город, который не находится в указанной стране?


person Mihail Shishkov    schedule 09.03.2013    source источник
comment
поскольку Country нужен только id города не знаю, очищаем CountryID при назначении CityID. Запрос будет IsNull (CountryFromCityLookUp, CountryLookup) в качестве страны.   -  person bummi    schedule 09.03.2013
comment
И каков правильный синтаксис для ограничения CHECK или TRIGGER? Спасибо.   -  person Mihail Shishkov    schedule 09.03.2013


Ответы (2)


Я не уверен, что это будет лучший способ, но вы можете добавить функцию и использовать ее в своем проверочном ограничении:

CREATE FUNCTION CheckCityInCountry(@CityID int, @CountryID int)
RETURNS int
AS 
BEGIN
   DECLARE @retval int
   SELECT @retval = COUNT(*) 
     FROM Cityies CI inner join Countries CO on (CI.CountryID, CO.ID)
     WHERE CO.CountryID = @CountryID and CityID = @CityID
   RETURN @retval
END;
GO

Эта функция вернет 1, если город находится в стране, и 0 в противном случае.

Затем добавьте контрольное ограничение, используя эту функцию:

ALTER TABLE Customers
ADD CONSTRAINT chk_CheckCityInCountry CHECK (
   CityID is null OR
   dbo.CheckCityInCountry(CityID,CountryID) >= 1
);
GO
person Mortalus    schedule 09.03.2013
comment
Это хорошая идея :) однако вы пропустили параметр CountryID CheckCityInCountry. Мы не пытаемся определить, существует ли вообще город, здесь мы хотим проверить, назначил ли Клиент страну, а затем кто-то назначает Город этому Клиенту, чтобы убедиться, что CountryID Города соответствует CountryID клиента. Спасибо за предложение. - person Mihail Shishkov; 09.03.2013
comment
Я был бы очень, очень, очень осторожен с использованием пользовательских функций в проверочных ограничениях. См. connect.microsoft.com/SQLServer/feedback/details/301828 (закрыто as не исправит), sqlblog.com/blogs/alexander_kuznetsov/archive/2009/06/25/ и sqlblog.com/blogs/tibor_karaszi/archive/2009/ 17.12. - person Aaron Bertrand; 09.03.2013
comment
Спасибо, Аарон. Вы знаете лучший способ сделать это? - person Mihail Shishkov; 09.03.2013

Настройте отношения FK для таблиц Country и City.

Измените таблицу City, чтобы она содержала составной PK из CountryID и CityID.
Это отношение FK должно ссылаться на оба.

FK не применяется к нулевому значению.

Одно предостережение: вы можете ввести неправильный CityID с нулевой страной, так как в этот момент ни FK не применяется.
Но я думаю, что это можно было бы применить с помощью CHECK CONSTRAINT.

ALTER TABLE dbo.CustomerCountyCity ADD CONSTRAINT CK_CustomerCountyCity
    CHECK (CountryID is not null OR CityID is Null)
person paparazzo    schedule 09.03.2013