SQL两列中的唯一约束条件

3

我在SQL中有一个表,希望设置唯一约束,以便任何两个值都不会重复存在。

例如,如果我有2列,我希望它在列B的值不存在于列A或列B时无法插入。

这是否可能,如果可能,如何实现?

示例:

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

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


@Veljko89 我们在后端使用EntityFramework,从中调用SQL,因此我们希望尽可能避免使用SP。 - LiamHT
@pancho018,请查看更新后的问题。 - LiamHT
@LiamHT,请考虑一个触发器。 - Dan Guzman
1
你的前两个句子是互斥的。你想要哪一个?是在A或B中必须存在的B中的新值,还是在A或B中不需要存在的B中的新值? - Gordon Linoff
存储过程和触发器的问题在于SQL Server旨在为并发事务提供隔离,因此这些“解决方案”在并发情况下会失败。我强烈建议重新审视数据模型以消除这种需求。 - Shannon Severance
显示剩余2条评论
3个回答

0
你可以创建一个函数,它接受这些值并在表上创建一个检查约束(参考你的函数返回值)。
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))

0

使用ROLLBACK TRANSACTION触发器是正确的方法。

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

如果插入操作没有在事务中完成,会怎样? - beercohol
2
触发器在执行时会像存在未完成的事务一样操作。无论触发器所触发的语句是隐式事务还是显式事务,这都是正确的。 - Anton
我已经接受了你的答案,即使我并没有去做。我们决定不进行添加触发器的大修,因为这个限制并不是百分之百必要的,只是一个很好的附加项。 - LiamHT
@Anton - 好的,我没意识到(或者忘记了)这一点! 那么,我的问题应该是:“如果触发器在更高级别事务的上下文中被触发,整个事务回滚将是不可取的,怎么办?” - beercohol

0

当需要强制执行数据库引擎不提供的多行约束时,显而易见的解决方案是使用触发器或存储过程。然而,这种方法通常无法奏效,因为数据库会隔离触发器和存储过程运行的事务,从而允许在并发情况下违反约束。

相反,应将约束转化为数据库引擎可以强制执行的形式。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接