SQL 服务器:看起来有序的唯一组合键

SQL Server: Unique Composite Key that looks order

我创建了一个小测试 table,其中包含 2 个整数列 pkId1pkId2。我将主键设置为包含两列的组合,(首先是 pkId1,然后是 pkId2)。

现在我按以下顺序插入了一些值:(1,1)(1,2)(2,1)(2,2)。我原以为 (2,1) 会失败,但事实并非如此。我怎样才能强制它失败?

我可以将其签入我的应用程序,但我想在 SQL 端进行。 另外,我想过使用存储过程,但我想知道在 table.

的设计器中是否有为复合键设置的设置

编辑

pkId1pkId2 的顺序很重要。例如,如果 (2,1) 已经在 table 中,则不应接受 (1,2)。这是因为该行表示两个实体之间的 link。因此,应该读出 (2,1) 从 2 到 1 的 link 和 (1,2) 从 1 到 2 的 link。

对于(1,1),(2,2)等两列相同的值,它们被接受,因为它们是一种特殊情况。

一个选项是创建一个 PERSISTED 列

例子

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TestTable](
    [pkId1] [int] NOT NULL,
    [pkId2] [int] NOT NULL,
    [pkuc]  AS (case when [pkId1]<[pkId2] 
                     then concat([pkId1],'-',[pkId2]) 
                     else concat([pkId2],'-',[pkId1]) 
                end) PERSISTED NOT NULL UNIQUE
) ON [PRIMARY]
GO

测试

Insert Into [dbo].[TestTable] (pkId1,pkId2) values (1,2)
Insert Into [dbo].[TestTable] (pkId1,pkId2) values (2,1)

Select * from [dbo].[TestTable]

已更新Table

pkId1   pkId2   pkuc
1       2       1-2

出现了两个相对简单的选项。


1.检查约束和“代替”触发器

如果我们创建约束 pkId1 <= pkId2,则可以满足要求,如 中所述。但是,问题是这也会阻止 (2,1) 的插入。

为了解决这个问题,我们在 table 上创建一个 INSTEAD OF 触发器来交换值:

CREATE TRIGGER TrgINS ON dbo.Table
INSTEAD OF INSERT AS

SET NOCOUNT ON;

INSERT dbo.Table (pkId1, pkId2)
SELECT
  IIF(pkId1 > pkId2, pkId2, pkId1),
  IIF(pkId1 > pkId2, pkId1, pkId2)
FROM inserted;

GO

2。强制执行约束的索引视图

我们在 table 上创建了一个索引视图,并交换了值。视图本身的唯一约束强制要求,因此 (2,1) 的单个插入不会被阻止, (2,1) 或 (1,2) 的进一步插入将被阻止:

CREATE VIEW vwTableUnique
WITH SCHEMABINDING AS

SELECT
  IIF(pkId1 > pkId2, pkId2, pkId1) AS pkId1,
  IIF(pkId1 > pkId2, pkId1, pkId2) AS pkId2
FROM dbo.Table;

GO

CREATE UNIQUE CLUSTERED INDEX CX_vwTableUnique ON dbo.Table (pkId1, pkId2);

GO