在两列上检查唯一性的有效方法?

Posted

技术标签:

【中文标题】在两列上检查唯一性的有效方法?【英文标题】:Efficient way to CHECK UNIQUE on two columns? 【发布时间】:2014-05-12 03:56:19 【问题描述】:

我在 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

业务规则

    总会有两个县。 这两个国家可以按任意顺序排列。位置 A 或 B 没有意义。 两个国家/地区的每个组合对表来说必须是唯一的。因此,AUS USA 被认为与 USA AUS 相同。 这两个国家永远不会相同。

问题

执行唯一性约束的最有效方法是什么?

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

【问题讨论】:

【参考方案1】:

您可以在两个条件下做到这一点。第一个是唯一索引(或约束):

create unique index AgreementParticipants_CountryA_CountryB on AgreementParticipants(CountryA, CountryB)

第二个是CountryA小于CountryB的条件:

check (CountryA < CountryB)

如果国家可能相同,则条件为&lt;=

这种方法的一个缺点是,在插入时,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);

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

【讨论】:

@MarkyMark 。 . .我修改了答案以给出两个解决方案。第一个要求这对是 AUS USA。第二个可以按任意顺序处理对。 谢谢 Gordon,我会试试你的解决方案,看看效果如何。 戈登,我正在检查您的答案,因为它有效并且有我需要的东西。谢谢。【参考方案2】:

约束如:

CHECK ( CountryA &lt; CountryB ) UNIQUE ( CountryA, CountryB )

是一种方法

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

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

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

【讨论】:

【参考方案3】:

通过为CountryA, CountryB 的每个组合投影一个唯一的“哈希”,可以将 Gordon 的第二个替代方案简化为一个计算列:

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

【讨论】:

感谢您向我介绍 SQL Fiddle,多么有用的网站!

以上是关于在两列上检查唯一性的有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UCanAccess 在两列上创建具有唯一约束的表?

在两列上创建索引以检查日期是不是介于这两个列之间

SQLite 表约束 - 在多个列上唯一

SQL 根据两列删除重复记录

索引视图的两列上的唯一聚集索引

两列上的 BigQuery 重复数据删除作为唯一键