首页 文章

是否可以实现特定于行的检查约束?

提问于
浏览
0

我有一个表,其中每一行代表一个键值对,其中包含特定于应用程序的设置(例如保留警报的天数等) . 这些键值对中的每一个都具有不同的有效值范围,因此没有单个检查约束将同等地应用于所有行 . 某些行可能根本不需要验证,而其他行可能需要特殊考虑的字符串值 . 有没有什么方法可以在每行的基础上创建一个检查约束,并在更新该行时强制执行该约束?

我已多次尝试实现这一目标,但每次都遇到障碍 . 每次尝试都依赖于表上存在[Check]列,其中为该行定义约束,类似于正常的基于表的约束(例如“((CAST Value AS INTEGER)<= 60)”) .

我的第一次尝试是创建一个正常的检查约束,该约束调用一个用户定义的函数,该函数读取[Check]列的内容(基于标识值),执行约束测试,并返回true / false结果,取决于是否违反约束 . 这种方法的问题在于它需要编写动态SQL来获取[Check]列的内容以及执行它包含的代码 . 但是,当然,函数中不允许使用动态SQL .

接下来,我尝试将函数更改为存储过程,但似乎无法通过检查约束调用存储过程 .

最后,我尝试创建一个函数和一个存储过程,并从函数中调用存储过程,但这也是不允许的 .

我知道的唯一方法是编写一个巨大的单片检查约束,包含按身份值检查每一行,所有OR一起,如下所示:

(ID = 1 AND(CAST值AS INTEGER)<= 100)OR(ID = 2 AND Value IN('yes','no'))或......

但这是一个容易出错的维护噩梦 . 有没有人知道如何实现我想要的方式,而不采用单片检查约束?

根据要求,请考虑以下表定义和一些示例行:

CREATE TABLE [dbo].[GenericSetting]
(
  [ID] [INT] IDENTITY(1,1) NOT NULL,
  [Name] [NVARCHAR](50) NOT NULL,
  [Value] [NVARCHAR](MAX) NULL,
  [Check] [NVARCHAR](MAX) NULL,
  CONSTRAINT [PK_GenericSetting] PRIMARY KEY CLUSTERED ([ID])
)

INSERT INTO [dbo].[GenericSetting] ([Name],[Value],[Check]) VALUES ('AlertRetentionDays', 60, 'CAST(Value AS INTEGER) <= 60');
INSERT INTO [dbo].[GenericSetting] ([Name],[Value],[Check]) VALUES ('ExampleMode', 60, 'CAST(Value AS INTEGER) IN (1,2,5)');

4 回答

  • 0

    检查约束并不是真的旨在做到这一点......你最好做的就是

    • 表上的验证触发器,它很糟糕,或者

    • 将所有写入实现为存储过程本身,否则禁用表的INS / UPD . 这也很糟糕 .

    冒着成为SO刻板印象的风险,您似乎将业务逻辑放在数据库层中...检查约束对于静态检查非常有用,但它们并非真正用于此之外 . 我也很想建议为解决方案寻找upteam(DA层或代码库的公共层) .

    是的,我在那里走了一点 . 提前抱歉 .

  • 0

    理论上,您可以通过标量UDF实现此类检查 . 但是,请注意它们可以是quite troublesome in such scenarios .

    考虑到您已经为系统选择了EAV设计方法,将UDF添加为检查约束可能会降低整体性能,从坏到坏 .

  • 0

    您可以使用条件逻辑编写此类检查约束 . 为了安全起见,这实际上是我将 case 用于布尔逻辑的情况:

    alter table eav add constraint chk_eav_value
        check (case when attribute = 'amount'
                    then (case when try_convert(int, value) >= 0 then 'ok' else 'bad' end)
                    when attribute = 'us_zip'
                    then (case when value like '[0-9][0-9][0-9][0-9][0-9]' then 'ok' else 'bad' end)
                    when attribute like 'city'
                    then (case when value not like '%[a-zA-Z ']%' then 'ok' else 'bad'
                    else 'ok'
                end) = 'ok');
    
  • 0

    您需要在此表上创建触发器才能完成此任务 .

相关问题