SQL Server 2008: могу ли я использовать ограничение для этого? - PullRequest
1 голос
/ 09 марта 2010

У меня есть таблица с тремя полями, User, City и Country, где ровно одно полей должно быть постоянно не NULL. Могу ли я использовать для этого ограничение SQL или переосмыслить то, что я делаю?

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

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

Мысли

Ответы [ 5 ]

1 голос
/ 09 марта 2010

Если я правильно понимаю, следующий SQL должен добавить искомое ограничение:

ALTER TABLE YourTableName
ADD CONSTRAINT CK_TestNullCount 
    CHECK (Case When [user] is NULL Then 0 Else 1 End 
           + Case When City Is NULL Then 0 Else 1 End 
           + Case When Country Is NULL Then 0 Else 1 End = 1)
0 голосов
/ 09 марта 2010

Я бы предложил придерживаться сценария FK. Вот как я могу убедиться, что документ привязан к одному и только к одному DocumentType (что вы называете прикрепленным).

Вот очень упрощенные отношения. Я понимаю, что у вас уже есть 3 столбца в вашей таблице документов, но подумайте над тем, чтобы сделать это FK. alt text

Затем загрузите типы документов с допустимым диапазоном значений.

alt text

При вставке данных вы будете писать тип как varchar, а не как int. Это не должно вызывать проблем с перфорированием и поможет вам в составлении отчетов и т. Д. С денормализованной схемой.

alt text

0 голосов
/ 09 марта 2010

Почему у вас нет двух столбцов, один с именем LocationId и один с именем LocationTypeId. Затем вы можете оставить соединение на всех трех столах:

SELECT COALESCE(User.Name, City.Name, Country.Name) 
FROM Location
INNER JOIN LocationType ON Location.LocationTypeId = LocationType.LocationTypeId
LEFT JOIN User ON Location.LocationId = User.Id AND Location.LocationTypeId = 1
LEFT JOIN City ON Location.LocationId = City.Id AND Location.LocationTypeId = 2
LEFT JOIN Country ON Location.LocationId = Country.Id AND Location.LocationTypeId = 3
0 голосов
/ 09 марта 2010

Не уверен, что вы можете сделать это с CHECK CONSTRAINT - я играю вокруг, но, кажется, ничего не получается в конце концов: - (

Но вы всегда можете создать триггер INSTEAD OF INSERT (и, возможно, INSTEAD OF UPDATE) для таблицы, чтобы проверить эти условия, и если они не выполняются, выведите исключение, используя RAISERROR, и строка не будет вставлена (или обновлено).

0 голосов
/ 09 марта 2010

Поместите их в одну таблицу Locations с столбцами LocationID, LocationName и (при необходимости) LocationType (Пользователь, Город, Страна). Вам нужно только одно объединение, чтобы обнаружить «местоположение» документа, и вам не нужно беспокоиться о том, какое поле выбрать, чтобы получить имя местоположения.

С помощью этой методики вы можете принудительно применить одно-единственное требование к местоположению с помощью простого ненулевого ограничения внешнего ключа.

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