简体   繁体   English

t-sql多个记录的单个默认值

[英]t-sql single default value for multiple records

I have an MSSQL Server 2008 table that associates multiple photos to houses, as follows: 我有一个MSSQL Server 2008表,将多张照片与房屋相关联,如下所示:

HouseID - with foreign key to House table
PhotoID - with foreign key to Photo table

It's all working great, with an unique constraint on PhotoID so that a photo cannot be associated with multiple houses. 一切都很好,对PhotoID具有独特的约束,因此照片不能与多个房屋相关联。

I would like to specify a default photo for the house records. 我想为房屋记录指定默认照片。 The table is updated as such 该表将这样更新

HouseID
PhotoID
isDefault

The issue is that there can only be a single isDefault = 1 for a set of photos for a house. 问题在于,一套房子的照片只能有一个isDefault = 1。

In MSSQL Server 2008, how do I ensure that there is only a single isDefault = 1 for a given House ID, and the other records are isDefault = 0? 在MSSQL Server 2008中,如何确保给定房屋ID只有一个isDefault = 1,而其他记录是isDefault = 0? Is it better to use a trigger, or is there a better way? 使用触发器更好还是有更好的方法? If a trigger, any suggestions on the syntax to ensure optimization? 如果是触发器,则对确保优化的语法有何建议?

Lastly, I need this to work on the Insert and on the Update events. 最后,我需要它来处理Insert和Update事件。

Update: 更新:

The following worked like a charm. 以下作品颇有魅力。 Comments? 评论?

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

As you describe it, you would need to use triggers. 正如您描述的那样,您将需要使用触发器。

However, if you make a small change to the data structure, you can do it with regular constraints, I think. 但是,我认为,如果对数据结构进行少量更改,则可以在常规约束下进行。 Instead of storing isDefault at the photo-level, store DefaultPhotoId at the house-level. 与其在照片级存储isDefaultDefaultPhotoId在房屋级存储DefaultPhotoId That way, you can never have more than one default photo, no matter what you do. 这样一来,无论您做什么,都不能拥有多个默认照片。

If you want to ensure that there is a default, then set it up as NOT NULL . 如果要确保存在默认值,则将其设置为NOT NULL

In MSSQL Server 2008, how do I ensure that there is only a single isDefault = 1 for a given House ID, and the other records are isDefault = 0? 在MSSQL Server 2008中,如何确保给定房屋ID只有一个isDefault = 1,而其他记录是isDefault = 0?

Why yes as Yves Samèr pointed out in this answer you can use use a filtered index 为什么是如YvesSamèr此答案中指出的那样,您可以使用过滤索引

CREATE UNIQUE INDEX photo_isDefault 
    ON Photos(HouseID) WHERE isDefault = 1 

DEMO 演示

The error that is produced is 产生的错误是

Cannot insert duplicate key row in object 'dbo.Photos' with unique index 'photo_isDefault'.: INSERT INTO Photos (houseID, isDefault) VALUES (1,1) 无法在具有唯一索引'photo_isDefault'的对象'dbo.Photos'中插入重复的键行。:INSERT INTO Photos(houseID,isDefault)值(1,1)

You could also opt to use a INDEXED VIEW or as you noted a trigger will do as well. 您还可以选择使用INDEXD VIEW,或者正如您提到的,触发器也可以。

I actually think that triggers might be overkill. 我实际上认为触发器可能会过大。 Just use CASE statements. 只需使用CASE语句即可。 Here's an example of the UPDATE statement (replacing the variables with whatever scripting language you're using): 这是UPDATE语句的示例(用您使用的任何脚本语言替换变量):

UPDATE HousePhoto
SET isDefault = 
(
    CASE
        WHEN
            (PhotoID = @PhotoID)
        THEN
            1
        ELSE
            0
    END
)
WHERE HouseID = @HouseId

Of course, you could always just use two queries. 当然,您始终可以只使用两个查询。

  UPDATE HousePhoto SET isDefault = 0 WHERE HouseID = @HouseID
  UPDATE HousePhoto SET isDefault = 1 WHERE HouseID = @HouseID AND PhotoID = @PhotoID

There another approach: use a "reverse" FK: 还有另一种方法:使用“反向” FK:

ER模型

[SQL Fiddle] [SQL提琴]

It is crucial to note the usage of the identifying relationship and the resulting composite PK in Photo : {HouseId, PhotoNo} . 至关重要的是要注意在Photo使用标识关系和合成的PK: {HouseId, PhotoNo} This serves two purposes: 这有两个目的:

  • Ensures that if a photo is the default of some house, it must belong to the same house. 确保如果照片是某些房屋的默认照片,则它必须属于同一房屋。
  • Makes the FK in House composite. 使FK in House复合。 Since one of the FK fields is also in the PK ( HouseId ), it cannot be NULL, so it is crucial to have another field that can be NULL ( DefaultPictureNo ). 由于FK字段之一也位于PK( HouseId )中,因此它不能为NULL,因此具有另一个可以为NULL的字段( DefaultPictureNo )至关重要。 If any of the FK fields is NULL, the FK is not enforced which allows us to break the chicken-and-egg problem when inserting new data 1 in the presence of such circular FKs. 如果任何 FK字段为NULL,则不会强制执行FK,这使我们能够在存在此类循环FK的情况下插入新数据1时解决“鸡与蛋”问题。

Compared to using isDefault flag and the associated filtered index, this approach makes the following tradeoffs: 与使用isDefault标志和关联的过滤索引相比,此方法进行了以下权衡:

  • PRO: Avoids the overhead of the extra field. PRO:避免额外字段的开销。 This is potentially important if the total number of pictures is very high compared to the number of default pictures. 如果图片总数比默认图片数高,这可能很重要。
  • CON: Makes it impractical to use auto-increment for Photo PK. 缺点:不能对Photo PK使用自动增量。
  • CON: MS SQL Server will complain if you try to use declarative referential actions (such as ON DELETE CASCADE) in the presence of such circular FKs. 缺点:如果您尝试在存在此类循环FK的情况下使用声明性引用操作(例如ON DELETE CASCADE),则MS SQL Server将抱怨。 You'll need to implement referential actions using triggers. 您将需要使用触发器来实现引用操作。 This is an MS SQL Server quirk not generally applicable to other DBMSes. 这是一个MS SQL Server怪癖,通常不适用于其他DBMS。
  • TIE: Interferes less with clustering in Picture , at the price of interfering more with clustering in House . TIE:对Picture 聚类产生较少的干扰,但要对House聚类产生更多的干扰。 2 2
  • PRO: It's applicable to DBMSes that don't support filtered indexes (not really important here, but worth a mention). PRO:它适用于不支持过滤索引的DBMS(这里并不重要,但值得一提)。

1 Ie enables us to insert a house without setting the default picture right away, which would be impossible since this is a new house and has no pictures yet. 1 Ie使我们能够插入房屋而无需立即设置默认图片,这将是不可能的,因为这是一栋新房屋,尚无图片。

2 Secondary indexes can be expensive in clustered tables, and the FK in House will need a supporting index. 2个辅助索引可以在集群表昂贵,而FK在House将需要一个支撑指数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM