SQL Server 触发器认为表中没有重复项
Posted
技术标签:
【中文标题】SQL Server 触发器认为表中没有重复项【英文标题】:SQL Server trigger thinks there's a duplicate in the table when there isn't 【发布时间】:2018-09-09 21:04:11 【问题描述】:我是一名新的 SQL 开发人员。在推荐之后,我改变了我的触发器(对于这个任务,我需要使用一个触发器,所以无法避免它),但我已经重新改变了我的触发器。我希望它防止其中包含的BikeID
外键在Rentals
表中重复。
这是我目前的代码:
CREATE TRIGGER BikeNotAvailable
ON dbo.SA_Rental
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM SA_Rental
INNER JOIN inserted i ON i.BikeID = dbo.SA_Rental.BikeID)
BEGIN
ROLLBACK
RAISERROR ('This bike is already being hired', 16, 1);
END
go
但是当我在Rentals
表中输入BikeID
时,即使BikeID
还没有出现在一行中,它仍然会引发错误 - 为什么? (我也在一个空表上测试过这个,它仍然会引发错误)
只是我数据的一些上下文,BikeID
是来自“自行车”表的主键,它作为外键共享到Rentals
表,不确定这是否与错误有关。
谁能帮我修复这个触发器,让它工作。
谢谢。
【问题讨论】:
你的触发器是一个AFTER INSERT
,所以你插入后这个值当然会存在于表中。最好使用唯一索引而不是触发器来执行此操作。
【参考方案1】:
好吧,因为它是一个 AFTER 触发器,所以触发器在 新记录添加到表中之后运行(至少对您的触发器可见)。
假设您的表有一个自动生成的 ID 列,您应该像这样从检查中排除插入的行:
CREATE TRIGGER BikeNotAvailable ON dbo.SA_Rental
AFTER INSERT
AS
if exists ( select * from SA_Rental
inner join inserted i on i.BikeID=dbo.SA_Rental.BikeID
where SA_Rental.RentalID <> i.RentalID)
begin
rollback
RAISERROR ('This bike is already being hired', 16, 1);
end
go
【讨论】:
您好,感谢您的回复@wolfgang Kais。我已经尝试过了,但它不起作用。 BikeID 实际上是一个 varchar(50),那么我将如何更改上面的代码以使其工作?谢谢。 @NoName788 我不建议对 BikeID 做任何事情。 Rentals 表的主键是什么? 出租表的主键是'RentalID',它是一个整数 @NoName788,是的,这是我的假设,也是我建议在附加的 WHERE 子句中比较的内容。那么什么不起作用? (刚刚编辑了我的回复并将 ID 替换为 RentalID) 抱歉,我的错。我误会了,非常感谢你的魅力! :D【参考方案2】:实现您所追求的更简单的方法是创建唯一索引:
CREATE UNIQUE INDEX BikeRented ON SA_Rental (BikeID);
当然,假设当自行车不再租用时,您从表中删除了该行(因为这是您帖子中的隐含逻辑)。如果不是这种情况,那么我们需要更多细节;什么在您的桌子上说明租赁已经完成?
如果我们假设您有一个归还日期,并且归还日期是NULL
,此时自行车尚未归还,那么您将使用过滤索引像这样:
CREATE UNIQUE INDEX BikeRented ON SA_Rental (BikeID)
WHERE ReturnedDate IS NULL;
【讨论】:
嗨拉穆,感谢您的回复。 Wolfgang Kais 的建议满足了我的需要,主要是让自行车无法使用,我需要根据需要使用触发器。但感谢您抽出宝贵时间回复。以上是关于SQL Server 触发器认为表中没有重复项的主要内容,如果未能解决你的问题,请参考以下文章