针对SQL Server约束增强的两点建议

来源:互联网 发布:淘宝权回lgd 编辑:程序博客网 时间:2024/06/07 08:55

 

Two suggestions to enhance constraints in SQL Server http://sqlblog.com/Themes/default/images/common/star-left-off.gifhttp://sqlblog.com/Themes/default/images/common/star-right-off.gifhttp://sqlblog.com/Themes/default/images/common/star-left-off.gifhttp://sqlblog.com/Themes/default/images/common/star-right-off.gifhttp://sqlblog.com/Themes/default/images/common/star-left-off.gifhttp://sqlblog.com/Themes/default/images/common/star-right-off.gifhttp://sqlblog.com/Themes/default/images/common/star-left-off.gifhttp://sqlblog.com/Themes/default/images/common/star-right-off.gifhttp://sqlblog.com/Themes/default/images/common/star-left-off.gifhttp://sqlblog.com/Themes/default/images/common/star-right-off.gif

Alexander Kuznetsov

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/04/two-suggestions-to-enhance-constraints-in-sql-server.aspx

We can tuck any logical expressions in CHECK constraints, but all foreign keys are currently capable of right now is to verify that one or more column values are equal. In many cases it would be very useful to have foreign keys use more complex logical expressions. Also in some cases the ability to create constraints on indexed views would be very handy too. I will provide examples and hopefully we will come up with Connect items to vote for.

When more complex logical expressions in foreign keys are useful

Consider the following simple common sense rule: the maximum current of your device cannot exceed the maximum current of the circuit you plug it into. Suppose that the following tables store data about circuits and devices:

 

我们可以在CHECK的约束条件中加入任何逻辑表达式,而目前所有外键只能用来验证一个或多个列的值是否相等。 在许多情况下,对外键使用更复杂的逻辑表达式是非常有用的。 此外,在某些情况下能够在索引视图创建约束也将非常实用。 我将举例说明,同时我希望针对此文的投票链接会尽快加上。

当外键中需要更为复杂的逻辑表达式时

考虑下面的简单常识: 您的设备的最大电流不能超过您插入到它的电路的最大电流。 假设下面的表存储电路和设备数据:

CREATE TABLE Data.Curcuits(CurcuitID INT NOT NULL

  CONSTRAINT PK_Curcuits PRIMARY KEY,

  MaximumCurrent INT NOT NULL,

  Description VARCHAR(100) NOT NULL);

GO

INSERT INTO Data.Curcuits(CurcuitID,

  MaximumCurrent,

  Description)

SELECT 1, 25, 'Deck and Garage';

GO

CREATE TABLE Data.Devices(DeviceID INT NOT NULL

  CONSTRAINT PK_Devices PRIMARY KEY,

  CurcuitID INT NULL,

  MaximumCurrent INT NOT NULL,

  Description VARCHAR(100) NOT NULL,

  CONSTRAINT FK_Devices_Curcuits FOREIGN KEY(CurcuitID)

    REFERENCES Data.Curcuits(CurcuitID)

  );

GO

 

It would be very convenient to issue a simple command and implement this business rule:

 一个非常简便的命令就可能实现这个业务规则:

ALTER TABLE Data.Devices ADD CONSTRAINT FK_Devices_Curcuits

  FOREIGN KEY(CurcuitID, MaximumCurrent)

  REFERENCES Data.Curcuits(CurcuitID, MaximumCurrent)

 MATCH ON((Data.Devices.CurcuitID = Data.Curcuits.CurcuitID) AND

 (Data.Devices.MaximumCurrent <= Data.Curcuits.MaximumCurrent));

 

However, it is not supported, so I need to use a workaround, one more column and three constraints instead of one, as follows:

然而,该语句并不被支持,所以必须采用其他办法——多增加一列约束,使用3个而不是1个约束,如下所示:

ALTER TABLE Data.Curcuits

  ADD CONSTRAINT UNQ_Curcuits UNIQUE(CurcuitID, MaximumCurrent);

GO

ALTER TABLE Data.Devices ADD CurcuitMaximumCurrent INT NULL;

GO

ALTER TABLE Data.Devices DROP CONSTRAINT FK_Devices_Curcuits;

GO

ALTER TABLE Data.Devices ADD CONSTRAINT FK_Devices_Curcuits

  FOREIGN KEY(CurcuitID, CurcuitMaximumCurrent)

  REFERENCES Data.Curcuits(CurcuitID, MaximumCurrent)

  ON UPDATE CASCADE;

GO

ALTER TABLE Data.Devices

  ADD CONSTRAINT CHK_Devices_SufficientCurcuitMaximumCurrent

  CHECK(CurcuitMaximumCurrent >= MaximumCurrent);

GO

You can verify that the constraints work:

 你可以验证该约束有效:

INSERT INTO Data.Devices(DeviceID,

  CurcuitID,

  MaximumCurrent,

  CurcuitMaximumCurrent,

  Description)

SELECT 1, 1, 50, 25, 'Electric car charger'

 

Msg 547, Level 16, State 0, Line 1

The INSERT statement conflicted with the CHECK constraint "CHK_Devices_SufficientCurcuitMaximumCurrent". The conflict occurred in database "Test", table "data.Devices".

The statement has been terminated.

INSERT 语句和CHECK约束"CHK_Devices_SufficientCurcuitMaximumCurrent"发生冲突 该冲突发生在数据库"Test""data.Devices"

 该语句被终止执行。

 As you have seen, the implementation of a very simple and very common business rule is quite involved, because such business rules are not directly supported by the database engine.

 可以看出,一个非常简单而普通的业务规则实现起来也相当繁杂,因为数据库引擎并不直接支持这种业务规则。

When you want to create constraints on indexed views

 在索引视图上创建约束

Even when your database guarantees that “the maximum current of your device cannot exceed the maximum current of the circuit you plug it into”, it is not good enough. Consider the following sample data:

 尽管数据库保证“您的设备的最大电流不能超过您插入到它的电路的最大电流”,但这还不够。请看下列示例数据:

INSERT INTO Data.Devices(DeviceID,

  CurcuitID,

  MaximumCurrent,

  CurcuitMaximumCurrent,

  Description)

SELECT 2, 1, 15, 25, 'ShopVac';

 

INSERT INTO Data.Devices(DeviceID,

  CurcuitID,

  MaximumCurrent,

  CurcuitMaximumCurrent,

  Description)

SELECT 3, 1, 15, 25, 'Miter Saw';

 

The database structure allows to plug more than one device into a circuit, which is correct, but if you turn both devices on, their combined maximum current exceeds the circuit’s maximum current. To enforce this business rule, it would be natural to create an indexed view, so that the database guarantees that the totals are always correct:

 数据库中的数据表明可以插入一个以上的设备到电路,这没有错,可是当所有的设备都打开时,它们的最大电流之和会超过电路最大电流。为了加强这个业务规则,很自然的会创建一个索引视图以使数据库保证电流之和总是正确的。

CREATE VIEW Data.TotalMaximumCurrentPerCircuit WITH SCHEMABINDING

AS

SELECT d.CurcuitID,

  c.MaximumCurrent AS CircuitMaximumCurrent,

  SUM(d.MaximumCurrent) AS TotalMaximumCurrent,

  COUNT_BIG(*) AS NumDevices

FROM Data.Devices d JOIN Data.Curcuits c ON d.CurcuitID = c.CurcuitID

GROUP BY d.CurcuitID, c.MaximumCurrent;

GO

CREATE UNIQUE CLUSTERED INDEX Data_TotalMaximumCurrentPerCircuit

ON Data.TotalMaximumCurrentPerCircuit(CurcuitID);

GO

 

If I could create a check constraint on that indexed view, I would be all set:

 如果能在该索引视图上创建一个约束,我将进行这样的设置:

ALTER VIEW Data.TotalMaximumCurrentPerCircuit

  ADD CONSTRAINT CHK_TotalMaximumCurrentPerCircuit_ValidCurcuit

  CHECK(TotalMaximumCurrent <= CircuitMaximumCurrent)

 

 

Instead, I need to use triggers or rather contrived kludges. A built in native support for such quite common business rules would increase the usefulness of SQL Server.

实际上,我必须使用触发器或者精心拼凑Check约束来实现。如果数据库内置支持这种相当普遍的业务规则,那将会增加SQL Server的实用性

I have not created anything on Connect yet, because the ideas are kind of raw yet. I am very interested in your feedback. What do you think?

 This continues the series on denormalizing, which started with this post about working hours and appointments 


and continued with this post about running totals.

 

and a post about Storing intervals of time with no overlaps

Using ROWVERSION to enforce business rules

 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 农村无证宅基地怎么办 身份证没磁怎么办护照 买安置房怎么办产权 安置房房东违约怎么办 安置房产权到期怎么办 安置房怎么办房产证吗 美甲后指甲长了怎么办 在菲律宾怎么办持枪证? 绝地求生打不准怎么办 身份证号码变更后社保怎么办 社保与身份不符怎么办 年龄改了学籍怎么办 结婚证信息错误怎么办 六级身份证过期怎么办 身份号泄露了怎么办 身体证信息泄露怎么办 手机号被泄漏了怎么办 姓名和电话泄露怎么办 个人身份证信息泄露怎么办 身份号码泄露了怎么办 我身份证泄露了怎么办 身份证信息泄漏了怎么办 无锡身份证丢了怎么办 人在外地怎么办身份证 欠空放公司不还怎么办 兼职要身份证照片怎么办 身份证刷不了磁怎么办 身份证不能刷了怎么办 身份证指纹错了怎么办 指纹手机丢了怎么办 异地办理临时身份证怎么办 杭州办理外地身份证怎么办 办理身份证没有户口本怎么办 2018身份证掉了怎么办 双户口注销社保怎么办 常用户口被注销怎么办 刚到厦门怎么办身份证 新疆身份证丢了怎么办 技能证书丢了怎么办 16岁拍身份证怎么办 16岁以下怎么办身份证