如何解决SQL Server:看起来有序的唯一复合键
我创建了一个包含 2 个整数列 pkId1
和 pkId2
的小型测试表。我将主键设置为包含两列的组合(首先是 pkId1
,然后是 pkId2
)。
现在我按以下顺序插入了一些值:(1,1)
、(1,2)
、(2,1)
和 (2,2)
。我原以为 (2,1)
会失败,但它没有。我怎样才能强迫它失败?
我可以将其签入我的应用程序,但我想在 sql 端执行此操作。 另外,我考虑过使用存储过程,但我想知道表的设计器中是否有为复合键设置的设置。
编辑
pkId1
和 pkId2
的顺序很重要。例如,如果 (2,1) 已经在表中,则不应接受 (1,2)。这样做的原因是因为该行表示两个实体之间的链接。因此,应该读到有一个从 2 到 1 的链接(2,1)和一个从 1 到 2 的链接(1,2)。
至于 (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]
更新表格
pkId1 pkId2 pkuc
1 2 1-2
,
出现了两个相对简单的选项。
1.检查约束和“代替”触发器
如果我们创建约束 for row in open(path):
idx = 0
real_idx = idx + 1
with open(path,"r") as c:
emotion,image,usage = c.readlines()[real_idx].split(",")
if usage == "Training\n":
train_labels.append(int(emotion))
imageArr = []
imageArr.append(image)
train_images.append(imageArr)
elif usage == "PublicTest\n" or usage == "PrivateTest\n":
test_labels.append(int(emotion))
imageArr = []
imageArr.append(image)
test_images.append(imageArr)
else:
print("This row was not assigned to any usage!")
idx += 1
def load_data():
return train_images,train_labels,test_images,test_labels
format_data(path)
load_data()```
,则可以满足要求,如 SMor's comment 中所述。然而,问题是这也会阻塞 (2,1) 的插入。
为了解决这个问题,我们在表上创建了一个 pkId1 <= pkId2
触发器来交换值:
INSTEAD OF
2.强制执行约束的索引视图
我们在表上创建了一个索引视图,并交换了值。视图本身的唯一约束强制执行该要求,因此 (2,1) 的单个插入不会被阻止,(2,1) 或 (1,2) 的进一步插入被阻止:
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。