我使用SQL Server 2008,我有两个现有表venues
和events
。
我正在尝试使用检查约束创建自定义函数,以确保event_expected_attendance
表中events
列中的整数始终小于或等于venue_max_capacity
venues
表中的整数。
我正在努力使用自定义函数的语法以及join语句,因为检查约束在两个表之间。
感谢您的帮助!我会尽快回答任何其他问题。
答案 0 :(得分:13)
正如Martin Smith所说,使用UDF的检查约束有一些问题,可能会对性能产生负面影响,但如果你想尝试它,那么这段代码应该可以工作:
CREATE FUNCTION dbo.CheckVenueCapacity (@venue_id int, @capacity int)
RETURNS int
AS
BEGIN
DECLARE @retval int
SELECT @retval = CASE WHEN venue_max_capacity >= @capacity THEN 0 ELSE 1 END
FROM venues
WHERE venue_id = @venue_id
RETURN @retval
END;
GO
ALTER TABLE events
ADD CONSTRAINT chkVenueCapacity
CHECK (dbo.CheckVenueCapacity(event_venue_id, event_expected_attendance) = 0);
答案 1 :(得分:11)
您可以为此使用标量UDF,但在检查约束中使用这些UDF会有很好的记录问题(例如,请参阅Scalar UDFs wrapped in CHECK constraints are very slow and may fail for multirow updates或Snapshot isolation: A threat for integrity?系列。
也可以让数据库引擎使用索引视图强制执行此操作
它需要一个包含2行作为CTE的帮助器表,并且在索引视图中不允许UNION
。我们的想法是视图定义应始终返回零行,如果存在违规,则会将所返回的行加倍。因此导致违反视图上的唯一约束并导致错误发生并且语句失败。
CREATE TABLE dbo.TwoNums
(
Num INT PRIMARY KEY
)
INSERT INTO dbo.TwoNums
VALUES (1),
(2)
然后是视图定义
CREATE VIEW dbo.PreventOverCapacity
WITH SCHEMABINDING
AS
SELECT V.Venueid,
E.EventId,
E.Expected,
V.Capacity
FROM dbo.Venues V
JOIN dbo.Events E
ON E.venueid = V.venueid
AND E.Expected > V.Capacity
CROSS JOIN dbo.TwoNums
视图上的唯一索引
CREATE UNIQUE CLUSTERED INDEX [UIX_PreventOverCapacity (Venueid, EventId, Expected, Capacity)]
ON dbo.PreventOverCapacity(Venueid, EventId, Expected, Capacity)
包含所有四列的原因是所有必需的值都显示在错误消息中。
无法在对象'dbo.PreventOverCapacity'中插入重复的键行 具有唯一索引'UIX_PreventOverCapacity(Venueid,EventId, 预期,容量)' 重复键值为(1,97,110,100)。