Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
两列中任意一列上的SQL唯一约束_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

两列中任意一列上的SQL唯一约束

两列中任意一列上的SQL唯一约束,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我在SQL中有一个表,我希望有一个唯一的约束,这样两个值中的任何一个都不能存在 例如,如果我有2列,如果列B中的值在列A或列B中不存在,我希望它不插入 这可能吗?如果可能,如何做到 例如: Column A | Column B -------------------- 4 | 6 我希望任何试图在表中插入4或6的对象都不被允许您可以创建一个接受这些值的函数,并在其上创建一个检查约束,引用函数将值返回到表中 create table t11 (Code int, code2

我在SQL中有一个表,我希望有一个唯一的约束,这样两个值中的任何一个都不能存在

例如,如果我有2列,如果列B中的值在列A或列B中不存在,我希望它不插入

这可能吗?如果可能,如何做到

例如:

Column A | Column B
--------------------
     4   |   6

我希望任何试图在表中插入4或6的对象都不被允许

您可以创建一个接受这些值的函数,并在其上创建一个检查约束,引用函数将值返回到表中

create table t11 (Code int, code2 int)

create function fnCheckValues (@Val1 int, @Val2 int)
Returns int /*YOu can write a better implementation*/
as
Begin
 DECLARE @CntRow int  
 IF(@Val1 IS NULL OR @Val2 IS NULL) RETURN 0    
 select @CntRow = count(*)  from t11   
    where Code in (@Val1,@Val2 ) or Code2 in (@Val1,@Val2 ) 

 RETURN @CntRow  
End

GO

alter table t11 Add constraint CK_123 check ([dbo].[fnCheckValues]([Code],[code2])<=(1))

带回滚事务的触发器是一种方法

create trigger dbo.something after insert as
begin
    if exists ( select * from inserted where ...check here if your data already exists... )
    begin
        rollback transaction
        raiserror ('some message', 16, 1)
    end
end

当需要强制执行数据库引擎不提供的多行约束时,显而易见的解决方案是使用触发器或存储过程。这通常不起作用,因为数据库隔离了触发器和存储过程在其中运行的事务,从而允许出现并发冲突

相反,将约束转化为数据库引擎将强制执行的内容

CREATE TABLE dbo.T (A INT, B INT)
GO

CREATE TABLE dbo.T_Constraint_Helper (ColumnName sysname PRIMARY KEY)
INSERT INTO dbo.T_Constraint_Helper (ColumnName)
VALUES ('A'), ('B')
GO

CREATE VIEW T_Constraint_VW 
WITH SCHEMABINDING AS 
SELECT CASE CH.ColumnName WHEN 'A' THEN T.A ELSE T.B END AS Value
FROM dbo.T
CROSS JOIN dbo.T_Constraint_Helper CH
GO

CREATE UNIQUE CLUSTERED INDEX FunnyConstraint_VW_UK ON dbo.T_Constraint_VW (Value)
GO

INSERT INTO T VALUES (1, 2)
-- works
INSERT INTO T VALUES (2, 3)
-- Msg 2601, Level 14, State 1, Line 1
-- Cannot insert duplicate key row in object 'dbo.T_Constraint_VW' with unique index 'T_Constraint_VW_UK'. The duplicate key value is (2).
INSERT INTO T VALUES (4, 4)
-- Msg 2601, Level 14, State 1, Line 1
-- Cannot insert duplicate key row in object 'dbo.T_Constraint_VW' with unique index 'T_Constraint_VW_UK'. The duplicate key value is (4).
INSERT INTO T VALUES (5, 6)
-- works

你不能只做一些存储过程来执行IF-Exists插入,而不是使用约束吗?请提供一些示例data@Veljko89我们在后端使用EntityFramework,从中调用sql,因此我们希望尽可能避免SPpossible@pancho018见更新的问题你的前两句话是相互排斥的。你想要哪个?B中要求在A或B中的新值,或B中要求不在A或B中的新值。如果插入不是在事务中完成的,该怎么办?执行触发器时,触发器的操作就像存在有效的未完成事务一样。无论触发触发器的语句是隐式事务还是显式事务,这都是正确的。尽管我没有这样做,但我已经接受了你的答案。我们已经决定,添加触发器的彻底检查不值得100%不必要的约束,只是一个很好的添加。@Anton-很公平,我没有意识到或者已经忘记了这一点!在这种情况下,我的问题应该是,如果触发器是在更高级别事务的上下文中触发的,那么回滚整个事务将是不可取的,那么该怎么办?