我有一个MSSQL Server 2008表,它将多张照片关联到房屋,如下所示:
HouseID - with foreign key to House table
PhotoID - with foreign key to Photo table
这一切都很有效,PhotoID上有一个独特的约束条件,因此照片无法与多个房屋相关联。
我想为房屋记录指定默认照片。该表如此更新
HouseID
PhotoID
isDefault
问题是,对于一套房子的照片,只能有一个isDefault = 1。
在MSSQL Server 2008中,如何确保给定的House ID只有一个isDefault = 1,其他记录是isDefault = 0?使用触发器更好,还是有更好的方法?如果是触发器,对语法有什么建议可以确保优化吗?
最后,我需要这个来处理Insert和Update事件。
更新
以下工作就像一个魅力。评论
CREATE VIEW HousePhoto_isDefault AS
SELECT yourSchema.HousePhoto.houseID, yourSchema.HousePhoto.isDefault
FROM yourSchema.HousePhoto WHERE isDefault = 1
GO
CREATE UNIQUE CLUSTERED INDEX idx_HousePhoto_isDefault
ON HousePhoto_isDefault (houseID)
GO
答案 0 :(得分:0)
正如您所描述的那样,您需要使用触发器。
但是,如果你对数据结构做了一些小改动,我认为你可以通过常规约束来做到这一点。而不是在照片级别存储isDefault
,而是将DefaultPhotoId
存储在房屋级别。这样,无论你做什么,你都不会有多张默认照片。
如果您想确保有默认值,请将其设置为NOT NULL
。
答案 1 :(得分:0)
在MSSQL Server 2008中,如何确保给定的House ID只有一个isDefault = 1,其他记录是isDefault = 0?
为什么是Yves Samèr指出this answer你可以使用过滤索引
CREATE UNIQUE INDEX photo_isDefault
ON Photos(HouseID) WHERE isDefault = 1
产生的错误是
无法在对象'dbo.Photos'中插入重复的关键行 index'photo_isDefault':插入照片(houseID,isDefault) 价值观(1,1)
你也可以选择使用INDEXED VIEW,或者你也注意到触发器也会这样做。
答案 2 :(得分:0)
我实际上认为触发器可能过度杀伤。只需使用CASE语句。以下是UPDATE语句的示例(使用您正在使用的任何脚本语言替换变量):
UPDATE HousePhoto
SET isDefault =
(
CASE
WHEN
(PhotoID = @PhotoID)
THEN
1
ELSE
0
END
)
WHERE HouseID = @HouseId
当然,你总是可以使用两个查询。
UPDATE HousePhoto SET isDefault = 0 WHERE HouseID = @HouseID
UPDATE HousePhoto SET isDefault = 1 WHERE HouseID = @HouseID AND PhotoID = @PhotoID
答案 3 :(得分:0)
还有另一种方法:使用“反向”FK:
在Photo
:{HouseId, PhotoNo}
中注意identifying关系和最终复合PK的使用至关重要。这有两个目的:
House
复合中的FK成为可能。由于其中一个FK字段也在PK(HouseId
)中,因此它不能为NULL,因此使另一个可以为NULL的字段(DefaultPictureNo
)至关重要。如果任何的FK字段为NULL,则不会强制执行FK,这样我们就可以在存在此类数据的情况下插入新数据 1 时打破鸡与蛋的问题圆形FK。与使用isDefault
标志和关联的过滤索引相比,此方法进行了以下权衡:
Photo
PK使用自动增量是不切实际的。Picture
中clustering的干扰较少,代价是干扰House
中的聚类。 2 1 I.e。使我们能够插入一个房子而不立即设置默认图片,这是不可能的,因为这是一个新房子,还没有图片。
2 在群集表中,辅助索引可能很昂贵,House
中的FK需要支持索引。