SQL 服务器 : User Defined Function In Check Constraint

标签 sql sql-server

我有一个表格,用于跟踪数据是否已在特定时间段内传输。这是一个简短的示例(省略了很多列,但这应该足够了):

+----+--------+------------+------+
| 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/

相关文章:

sql-server - SQL Server 2008 R2 智能感知不起作用

sql - 与日历比较查找缺失的日期

sql - 是否可以更改Sql Server中的数据类型Date

sql - 计数值不丢失的地方

php - Mysql:选择指定点之间的所有数据

sql - 将 0 填充到返回的查询并插入到临时表中

sql - 如何将 JSON 映射到 SQL 架构?

c# - 连接字符串无效或定位服务器/实例时出错

sql - 使用 PK 将行插入 SQL Server 表中特定位置

mysql - 如何在EXCEL或SQL中转置动态矩阵数据集