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

时间:2018-12-09 00:19:24

标签: sql sql-server check-constraints

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

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

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

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

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

我知道唯一可行的方法是编写一个巨大的整体检查约束,该约束包含按标识值对每一行进行的检查,将所有“或”运算在一起,如下所示:

(ID = 1 AND(整数值整数)<= 100)OR(ID = 2 AND值IN('是','否'))或...

但这是易于出错的维护噩梦。有谁知道一种无需借助整体检查约束就能完成我想要的方法的方法吗?

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

{{1}}

4 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分: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');

答案 2 :(得分:0)

检查约束arent确实旨在做到这一点...您最好能做到的

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

  • 将所有写操作本身实现为存储的proc,否则禁用表的INS / UPD。这也很糟糕。

冒着成为SO刻板印象的风险,您好像将业务逻辑放在db层中。检查约束对于静态检查非常有用,但实际上并没有超出这些限制。我很想建议您也寻找上游解决方案(DA层或代码库的公共层)以寻求解决方案。

是的,我在那儿走了一点。不好意思。

答案 3 :(得分:0)

理论上,您可以通过标量UDF实施这种检查。但是,请注意,它们可以是quite troublesome in such scenarios

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