在两列上检查UNIQUE的有效方法?

时间:2014-05-12 03:56:20

标签: sql sql-server

我在SQL Server 2012中有一个表,其中包含两个国家/地区的列,我们称之为CountryA和CountryB。

CREATE TABLE dbo.AgreementParticipants
(
    AgreementParticipantsID INT NOT NULL PRIMARY KEY IDENTITY,
    CountryA CHAR(3) NOT NULL FOREIGN KEY REFERENCES dbo.Country (CountryCode),
    CountryB CHAR(3) NOT NULL FOREIGN KEY REFERENCES dbo.Country (CountryCode)
);

注意:该表已经简化为示例,但重要的是始终定义两个实体之间的双边关系。恰好在这种情况下它是两个国家。

典型数据

1 AUS USA
2 USA NZL

业务规则

  1. 总会有两个县。
  2. 这两个国家可以处于任何一种秩序。位置A或B没有意义。
  3. 两个国家/地区的每个组合必须是唯一的。因此,AUS USA被认为与USA AUS相同。
  4. 这两个国家永远不会是一样的。
  5. 问题

    实施唯一性约束的最有效方法是什么?

    目前,我考虑使用触发器或复杂的检查约束,但这两种解决方案都不合适,所以我希望得到社区的一些意见。

3 个答案:

答案 0 :(得分:3)

您可以使用两个条件执行此操作。第一个是唯一索引(或约束):

create unique index AgreementParticipants_CountryA_CountryB on AgreementParticipants(CountryA, CountryB)

第二个条件是CountryA小于CountryB

check (CountryA < CountryB)

如果国家/地区可能相同,则条件为<=

这种方法的一个缺点是,在插入时,CountryA必须小于CountryB(按字母顺序排在第一位)。否则,这会产生错误。

另一种方法是使用计算列和唯一索引:

alter table AgreementParticipants
    add Country1 as (case when CountryA < CountryB then CountryA else CountryB end);

alter table AgreementParticipants
    add Country2 as (case when CountryA < CountryB then CountryB else CountryA end);

create unique index AgreementParticipants_Country1_Country2 on AgreementParticipants(Country1, Country2);

这种方法的优点是可以按任何顺序将国家/地区插入表格。

答案 1 :(得分:1)

约束如:

CHECK ( CountryA < CountryB ) UNIQUE ( CountryA, CountryB )

是一种方法

另一种方法是添加计算列,如:

CREATE TABLE t2 (CountryA ..., CountryB ... ,least_country as LEAST( CountryA, CountryB ) ,greatest_country as GREATEST( CountryA, CountryB ) )

然后对新列添加唯一约束。不确定SQLServer是否支持LEAST,但如果不支持,则很容易创建一个。

答案 2 :(得分:1)

通过投射一个独特的“哈希”,可以将戈登的第二个替代方案简化为一个计算列。 CountryA, CountryB的每个组合:

ALTER TABLE dbo.AgreementParticipants ADD CountryProjection AS
CASE WHEN CountryA < CountryB 
          THEN CountryA + '-' + CountryB 
          ELSE CountryB + '-' + CountryA
        END;

ALTER TABLE dbo.AgreementParticipants ADD CONSTRAINT U_AgreementParticipants 
UNIQUE (CountryProjection);

SqlFiddle here