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 触发器认为表中没有重复项的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 无法插入启用触发器的表中

SQL Server 删除触发器以更新同一表中的多个列

插入后使用 SQL Server 触发器更新另一个表中的列

SQL Server 在多个线程中插入死锁

SQL Server:原子触发器

创建触发器以了解谁在 SQL Server 表中进行了更改