我有一张桌子,不知怎的,同一个人进了我的person
桌子两次。现在,主键只是一个自动编号,但还有两个字段存在,我想强制它们是唯一的。
例如,这些字段是:
ID
Name
Active
PersonNumber
我只想要一张带有唯一PersonNumber和Active=1的唱片
(因此这两个字段的组合必须是唯一的)
SQL server中现有表的最佳方式是什么?我可以这样做,如果其他任何人使用与现有值相同的值进行插入,则插入失败,因此我不必在应用程序代码中担心这一点。
在我的例子中,我需要允许许多不活动,并且只允许两个键的一个组合处于活动状态,如下所示:
UUL_USR_IDF UUL_UND_IDF UUL_ATUAL
137 18 0
137 19 0
137 20 1
137 21 0
这似乎有效:
CREATE UNIQUE NONCLUSTERED INDEX UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL
ON USER_UND(UUL_USR_IDF, UUL_ATUAL)
WHERE UUL_ATUAL = 1;
以下是我的测试用例:
SELECT * FROM USER_UND WHERE UUL_USR_IDF = 137
insert into USER_UND values (137, 22, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 23, 0) --I CAN
insert into USER_UND values (137, 24, 0) --I CAN
DELETE FROM USER_UND WHERE UUL_USR_ID = 137
insert into USER_UND values (137, 22, 1) --I CAN
insert into USER_UND values (137, 27, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 28, 0) --I CAN
insert into USER_UND values (137, 29, 0) --I CAN
这也可以在GUI中完成:
删除副本后:
ALTER TABLE dbo.yourtablename
ADD CONSTRAINT uq_yourtablename UNIQUE(column1, column2);
或者
CREATE UNIQUE INDEX uq_yourtablename
ON dbo.yourtablename(column1, column2);
当然,在让SQL服务器尝试插入行并返回异常(异常代价高昂)之前,首先检查此违规通常会更好。
>
不同错误处理技术对性能的影响
在输入TRY/CATCH之前检查潜在的约束冲突
如果要防止异常冒泡到应用程序中,而不更改应用程序,可以使用而不是
触发器:
CREATE TRIGGER dbo.BlockDuplicatesYourTable
ON dbo.YourTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1 FROM inserted AS i
INNER JOIN dbo.YourTable AS t
ON i.column1 = t.column1
AND i.column2 = t.column2
)
BEGIN
INSERT dbo.YourTable(column1, column2, ...)
SELECT column1, column2, ... FROM inserted;
END
ELSE
BEGIN
PRINT 'Did nothing.';
END
END
GO
但是如果你不告诉用户他们没有执行插入,他们会想为什么数据不在那里,并且没有报告异常。
编辑这里是一个例子,它完全符合你的要求,甚至使用与你的问题相同的名称,并证明了这一点。你应该先尝试一下,然后再假设上面的想法只处理一个专栏或另一个专栏,而不是组合。。。
USE tempdb;
GO
CREATE TABLE dbo.Person
(
ID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(32),
Active BIT,
PersonNumber INT
);
GO
ALTER TABLE dbo.Person
ADD CONSTRAINT uq_Person UNIQUE(PersonNumber, Active);
GO
-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
VALUES(N'foo', 1, 22);
GO
-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
VALUES(N'foo', 0, 22);
GO
-- fails:
INSERT dbo.Person(Name, Active, PersonNumber)
VALUES(N'foo', 1, 22);
GO
所有这些之后的表格中的数据:
ID Name Active PersonNumber
---- ------ ------ ------------
1 foo 1 22
2 foo 0 22
上次插入时出现错误消息:
Msg 2627,14级,状态1,第3行违反唯一密钥约束“uq_Person”。无法在对象“dbo”中插入重复密钥。“人”。声明已被终止。
最近我还在博客上写了一个解决方案,可以将唯一约束按任意顺序应用于两列:
在顺序无关紧要的情况下强制执行唯一约束
问题内容: 我一直在尝试找出是否有可能对两列的组合具有唯一约束。 具体来说,我有两列A和B。 我有下面这样的行 然后我希望以下组合在插入时失败 我尝试添加一个简单的约束 但这让我在已经存在时插入。 这可能吗?还是在插入之前必须检查组合是否存在? 问题答案: 您可以使用表达式的索引来执行此操作: 我不认为约束允许表达式(并且现在没有方便的Postgres进行测试),但这本质上是同一回事。
问题内容: 我有三张桌子- 我想确保当它们自然连接时,product_id +文件名是唯一的。到目前为止,我拥有的最佳解决方案是将文件名添加到product_attachment表中,但是我想知道是否有避免这种情况的方法。 问题答案: 如果文件名列不是唯一的,则可以在表上添加自定义约束。请注意,这将在每次插入和更新时执行以下查询,这并不是理想的性能。
问题内容: 我想在我的MySQL表上添加一个唯一性约束。该表包含四列: 此约束必须检查对于new行,new和都未包含在或中。 例子 : 有没有办法定义这样的约束? 问题答案: 您可以通过触发器来做到这一点 注意: 由于您使用的MySQL版本缺少技巧,因此当找到具有相同地址的行时,违反对其中一列的约束。 这是 SQLFiddle 演示。取消注释最后一个插入语句之一,然后单击确定。这些插入不会成功。
我有下表: 我希望KEY_1和KEY_2的组合是唯一的,反之亦然。 这样,我可以使KEY_1和KEY_2之间的组合唯一,但我也希望相反。 示例: 我无法再次插入此值,反之亦然。 这应该是无效的(因为它是同一对密钥): 谢啦
问题内容: 我有一个带有4列的表格 每列将是A,B,C,D 列A是主键。列B具有唯一的名称约束。 现在,我想删除列B的唯一约束,并通过组合列B,C和D给出唯一约束。因此,该表将只允许一行包含列B,C和D中的特定值。 如何给这种约束? 我尝试给复合唯一密钥,例如: 但这是在检查是否存在任何约束,而不是在检查唯一键约束的组合。 问题答案: 在这些列上创建唯一键 Oracle / PLSQL:唯一约束
问题内容: 我有一种情况,我只想在其他字段中有特定值的情况下才添加唯一约束(例如表为ID CategoryName名称值Value CategoryID) 约束将在ID,CategoryName和Name上,只有CategoryID为0 是否有可能? 问题答案: