[英]SQL Server 2008: Can I use a constraint for this?
I have a table with three fields, User
, City
and Country
, where exactly one of the fields must be non- NULL
at all times. 我有一个包含三个字段的表: User
, City
和Country
,其中恰好其中一个字段必须始终为非NULL
。 Can I use an SQL constraint for this or should I rethink what I'm doing? 我可以为此使用SQL约束还是应该重新考虑我在做什么?
The scenario is that my database should contain documents that can be attached to users, cities or countries. 场景是我的数据库应包含可以附加到用户,城市或国家的文档。 So a row in this table contains exactly one document for either a user, a city or a country. 因此,此表中的一行仅包含一个针对用户,城市或国家的文档。 However, one should be able to search for all documents as well, regardless of what entity it has been "attached" to. 但是,无论文档被“附加”到哪个实体,都应该能够搜索所有文档。
The reason I'm not using three different tables instead is that I want to avoid having to JOIN
the three tables when searching for documents in all of the three places. 我之所以没有使用三个不同的表的原因是,我想避免在所有三个地方搜索文档时必须JOIN
三个表。 I'm imagining that the kind of denormalization I'm attempting to use here will improve performance, but I'm not sure. 我在想我要在这里使用的那种非规范化可以提高性能,但是我不确定。
Thoughts? 有什么想法吗?
If I understand properly, the following SQL should add the constraint you are looking for: 如果我理解正确,则以下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)
Put them in a single table Locations with columns LocationID, LocationName, and (if needed) LocationType (User, City, Country). 将它们放在具有位置ID,位置名称和(如果需要)位置类型(用户,城市,国家/地区)列的单个表位置中。 You need only a single join to discover the "location" of the document and you don't have to worry about which field to select to get the name of the location. 您只需一个联接即可发现文档的“位置”,而不必担心选择哪个字段来获取位置名称。
With this technique, you can enforce the "one and only one" location requirement with a simple non-null foreign key constraint. 使用此技术,您可以使用简单的非空外键约束来强制执行“一个且只有一个”位置要求。
Not sure if you can do it with a CHECK CONSTRAINT - I'm been playing around but nothing seems to really work in the end :-( 不知道您是否可以使用“检查约束”来完成它-我一直在玩,但是最后似乎没有任何效果:-(
But you could always create an INSTEAD OF INSERT
(and possibly an INSTEAD OF UPDATE
) trigger on the table to check these conditions, and if they're not met, throw an exception using RAISERROR and the row won't be inserted (or updated). 但是您总是可以在表上创建一个INSTEAD OF INSERT
(可能还有一个INSTEAD OF UPDATE
)触发器来检查这些条件,如果不满足,则使用RAISERROR引发异常,并且不会插入(或更新该行) )。
I'd suggest sticking with the FK scenario. 我建议坚持FK方案。 Here's how I'd ensure that a document is tied to one, and only one DocumentType
(what you're calling attached-to). 这是我要确保一个文档绑定到一个文档,并且只有一个DocumentType
(您称之为附件)的方式。
Here's a very simplified relationship. 这是一个非常简化的关系。 I realize you've already got the 3 columns on your Document table, but consider making that a FK. 我知道您的文档表上已经有3列,但是请考虑将其设为FK。
Then load up your Document types with the valid range of values. 然后使用有效范围的值加载您的文档类型。
When inserting data, you'll be writing the type as varchar, rather than an int. 插入数据时,您将把类型写为varchar,而不是int。 This shouldn't cause perf issues, and will help you in reporting, etc with the denormalized schema. 这不会引起性能问题,并且可以帮助您使用非规范化模式进行报告等。
Why don't you have two columns, one called LocationId and one called LocationTypeId. 为什么没有两列,一列称为LocationId,另一列称为LocationTypeId。 You can then left join onto all three tables: 然后,您可以将联接保留在所有三个表上:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.