我有一个包含ab和c列的表,如果c为false,那么我只想在列a和b是唯一的情况下允许插入,但如果c为true,那么a和b不需要是唯一的。< / p>
实施例: 表中只能有一个(foo,bar,false),但没有限制可以有多少(foo,bar,true)。
我尝试了类似CONSTRAINT的东西,但是UNIQUE(a,b)AND CHECK(C为TRUE),但我无法找出正确的语法。
答案 0 :(得分:9)
创建一个索引视图,使用过滤器WHERE C = false
返回a和b,然后在视图上创建唯一索引。这是一般方法
如果您有SQL Server 2008,则create a unique filtered index改为
存储过程
触发(之前或之后)
答案 1 :(得分:5)
所有行都有唯一约束,并且无法仅指定某些行。
检查约束仅适用于单行验证。
满足您要求的唯一方法是执行以下任何操作:
1)创建一个存储过程,其中包含所有INSERT。您可以在此验证所有逻辑。然而,流氓程序/用户可以避免使用它并打败你的逻辑。
2)创建一个触发器,验证您的逻辑并导致无效的插入/更新失败。应该写入一次处理一组行
3)创建一个检查约束,该约束调用用于执行验证检查的用户定义函数。这被认为是一种不好的做法,应该避免使用,因为它们非常慢并且可能无法进行多行更新。
我建议选项#2,触发器,因为这正是触发器的设计目的。
答案 2 :(得分:1)
您可以随时创建一个触发器,在插入之前检查所需的条件。
答案 3 :(得分:0)
您可以使用表约束(取决于SQL引擎 - 不清楚您正在使用哪个)以确保没有太多特定类型的元组。
在Firebird 2.1下:
fb> CREATE TABLE so2587151 (
> a VARCHAR(16) NOT NULL,
> b VARCHAR(16) NOT NULL,
> c VARCHAR(1) NOT NULL CHECK (c in ('T', 'F')),
> CONSTRAINT so2587151_only_one_false CHECK ( -- begin CONSTRAINT
> NOT EXISTS ( SELECT a, b, COUNT('x')
> FROM so2587151
> WHERE c = 'F'
> GROUP BY 1, 2
> HAVING COUNT('x') >= 1 )
> ) -- end CONSTRAINT
> );
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'T');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
fb> INSERT INTO so2587151(a,b,c) VALUES ('foo', 'bar', 'F');
Error: Operation violates CHECK constraint on view or table
-Operation violates CHECK constraint SO2587151_ONLY_ONE_FALSE on view or table SO2587151
-At trigger 'CHECK_15'
fb> SELECT * FROM so2587151;
A | B | C
==============
foo | bar | T
foo | bar | T
foo | bar | F
从约束违规错误消息中可以看出,这是根据Firebird的触发机制实现的。