我有一个表格,用于跟踪数据是否已在特定时间段内传输。这是一个简短的示例(省略了很多列,但这应该足够了):
+----+--------+------------+------+
| Id | DealId | Date | Sent |
+----+--------+------------+------+
| 1 | 1 | 2018-01-01 | 1 |
| 2 | 1 | 2018-02-01 | 1 |
| 3 | 1 | 2018-03-01 | 0 |
| 4 | 2 | 2018-01-01 | 1 |
| 5 | 2 | 2018-02-01 | 1 |
| 6 | 2 | 2018-03-01 | 0 |
| 7 | 1 | 2018-04-01 | 0 |
+----+--------+------------+------+
我想创建一个检查约束来防止插入最后一条记录。每个 DealId 不应允许超过一个 Sent = 0 行。 换句话说:如果该交易已经有 Sent = 0 行,则甚至不可能为 Sent = 0 的 DealId 插入一行。
这是带有约束的表脚本:
CREATE TABLE [Mrd].[Snapshot]
(
[Id] INT IDENTITY(1,1) CONSTRAINT [PK_Mrd_Snapshot_Id] PRIMARY KEY,
[DealId] INT NOT NULL,
[Date] DATETIME NOT NULL,
[Sent] BIT NOT NULL CONSTRAINT [DF_Mrd_Snapshot_Sent] DEFAULT 0,
CONSTRAINT [CK_Mrd_Snapshot_Sent]
CHECK ([Function].[ValidateSent]([DealId]) = 1)
)
这是函数脚本:
CREATE FUNCTION [Function].[ValidateSent]
(
@DealId INT
)
RETURNS BIT
AS
BEGIN
IF ((SELECT COUNT(*) FROM [Mrd].[Snapshot] WHERE [DealId] = @DealId AND [Sent] = 0) = 0)
BEGIN
RETURN 1;
END;
RETURN 0;
END
以及用于快速复制粘贴的模式创建:
CREATE SCHEMA [Function]
有了这个实现,我无法插入任何 Sent = 0 的行。 它会引发与检查约束的冲突错误。
关于我在约束或函数中做错了什么有什么建议吗? 或者也许有更好的方法来进行此检查?
谢谢!
最佳答案
我个人赞成在这种情况下使用唯一索引而不是约束。我发现我想要独一无二的列我可能想要一个索引,所以 2 只鸟和 1 block 石头。所以我会这样做:
CREATE UNIQUE NONCLUSTERED INDEX [uidx_dealid_sent] ON [dbo].[Snapshot]
(
[dealid] ASC,
[sent] ASC
)
WHERE ([sent]=0)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
复合唯一索引做你想做的事:你不能插入一行,其中特定的 dealid
和特定的 sent
已经存在。正如 Larnu 指出的那样,这应该是一个过滤索引(对于 MSSQL 2008 及更高版本)。注意 WHERE ([sent]=0)
,这应该满足您的要求,即只希望在 sent = 0
时应用规则。
关于SQL 服务器 : User Defined Function In Check Constraint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50910356/