两个字段的唯一约束,以及它们的相反

时间:2014-04-16 08:03:49

标签: sql sql-server sql-server-2008 unique

我有一个数据结构,我必须存储元素对。每对中都有2个值,因此我们使用了一个表,其中包含字段(leftvalue,rightvalue ....)。 这些对应该是唯一的,如果更改了密钥,则它们被认为是相同的。

Example: (Fruit, Apple) is the same as (Apple, Fruit).

如果能够以有效的方式实现,我会在字段上设置数据库约束,但不会付出任何代价 - 性能更重要。

我们目前正在使用MSSQL server 2008,但可以进行更新。

有没有一种有效的方法来实现这一目标?

4 个答案:

答案 0 :(得分:4)

两种解决方案,都是关于将问题变为更容易的问题。如果强迫对消费者做出改变,我通常更喜欢T1解决方案:

create table dbo.T1 (
    Lft int not null,
    Rgt int not null,
    constraint CK_T1 CHECK (Lft < Rgt),
    constraint UQ_T1 UNIQUE (Lft,Rgt)
)
go
create table dbo.T2 (
    Lft int not null,
    Rgt int not null
)
go
create view dbo.T2_DRI
with schemabinding
as
    select
        CASE WHEN Lft<Rgt THEN Lft ELSE Rgt END as Lft,
        CASE WHEN Lft<Rgt THEN Rgt ELSE Lft END as Rgt
    from dbo.T2
go
create unique clustered index IX_T2_DRI on dbo.T2_DRI(Lft,Rgt)
go

在这两种情况下,T1T2都不能包含Lft,Rgt对中的重复值。

答案 1 :(得分:1)

一种方法是创建一个计算列,它将两个值组合在一起并对其设置唯一约束:

create table #test (
    a varchar(10) not null, 
    b varchar(10) not null, 
    both as case when a > b then a + ':' + b else b + ':' + a end persisted unique nonclustered
    )

所以

insert #test
select 'apple', 'fruit'
insert #test
select 'fruit', 'apple'

给出

(1 row(s) affected)
Msg 2627, Level 14, State 1, Line 3
Violation of UNIQUE KEY constraint 'UQ__#test_____55252CB631EC6D26'. Cannot insert duplicate key in object 'dbo.#test'.
The statement has been terminated.

答案 2 :(得分:1)

如果您始终按顺序存储值,但将方向存储在另一列中,

CREATE TABLE [Pairs]
(
    [A] NVarChar(MAX) NOT NULL,
    [B] NVarChar(MAX) NOT NULL,
    [DirectionAB] Bit NOT NULL,
    CONSTRAINT [PK_Pairs] PRIMARY KEY ([A],[B]) 
)

您可以使用一个聚簇索引实现您想要的内容,并优化您的查找。

所以,当我插入'Apple', 'Fruit'对时,

INSERT [Pairs] VALUES ('Apple', 'Friut', 1);

很好,很容易。然后我插入'Fruit', 'Apple'

INSERT [Pairs] VALUES ('Apple', 'Fruit', 0); -- 0 becuase order is reversed.

插入失败,因为这是主键违规。为了进一步说明,对'Coconuts', 'Bananas'将存储为

INSERT [Pairs] VALUES ('Bananas', 'Coconuts', 0);

为了获得额外的查找性能,我添加了索引

CREATE NONCLUSTERED INDEX [IX_Pairs_Reverse] ON [Pairs] ([B], [A]);

如果您无法控制对表的插入,可能需要确保正确插入[A][B]

CONSTRAINT [CK_Pairs_ALessThanB] CHECK ([A] < [B])

但这可能会造成不必要的性能损失,具体取决于插件的控制程度。

答案 3 :(得分:0)