插入后触发多次插入后无法正常工作
Posted
技术标签:
【中文标题】插入后触发多次插入后无法正常工作【英文标题】:Trigger after insert not working correctly after multiple inserts 【发布时间】:2019-04-01 14:59:57 【问题描述】:我有一个在插入后触发的触发器。它触发一个存储过程,更新表CompanyStatus
中的列IsLast
Id | CompanyId | Status | DateCreated | IsLast
此存储过程应在IsLast
列中设置1
以获取最大Id
的记录。
CREATE PROCEDURE [dbo].[spCompanyStatusAfterInsert](@schemaName nvarchar(100), @dataTable CompanyStatus READONLY)
AS
BEGIN
DECLARE @sql nvarchar(max)
SELECT @sql = N'DECLARE
@Id bigint,
@companyId uniqueidentifier;
DECLARE CompanyStatus_Cursor CURSOR FAST_FORWARD FOR
SELECT Id, CompanyId
FROM @dataTable
OPEN CompanyStatus_Cursor
FETCH NEXT FROM CompanyStatus_Cursor
INTO @Id, @companyId
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE ' + QUOTENAME(@schemaName ) + N'.[CompanyStatus]
SET IsLast = 0
WHERE Id IN (SELECT Id
FROM ' + QUOTENAME(@schemaName) + N'.[CompanyStatus]
WHERE Id <> @Id
AND CompanyId = @companyId
AND IsLast = 1)
UPDATE ' + QUOTENAME(@schemaName) + N'.[CompanyStatus]
SET IsLast = 1
WHERE Id = @Id
FETCH NEXT FROM crs
INTO @Id, @companyId
END
CLOSE CompanyStatus_Cursor
DEALLOCATE CompanyStatus_Cursor'
EXEC sp_executesql @sql, N'@schemaName nvarchar(100), @dataTable CompanyStatus READONLY', @schemaName, @dataTable
END
(首先将所有现有的IsLast
更新为0
,然后将1
设置为最新的Id
- 这是预期的行为)。
问题 - 当我在很短的时间内进行 2 次插入时,我得到 2 条记录为 IsLast = 1
。
Id | CompanyId | Status | DateCreated | IsLast
19 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1 | 2019-04-01 12:08:59.540 | 1
18 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1 | 2019-04-01 12:10:57.790 | 1
17 | fc7d1f2b-a72a-4d7f-99fa-602c72fb0410 | 2 | 2019-03-30 12:14:57.294 | 1
16 | 8afbd9cb-02f9-45d7-a605-a54052866bd4 | 1 | 2019-03-29 12:10:57.790 | 0
在 ID 为 18
的示例行中不应使用 IsLast = 1
,因为存在 ID 较大的行。
这个更新查询的执行时间有问题吗? (第一次更新在第二次开始之前没有完成)。
触发码:
CREATE TRIGGER [schema].[schema_TRG_CompanyStatus]
ON [schema].[CompanyStatus]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE @dataTable CompanyStatus
INSERT INTO @dataTable SELECT Id, CompanyId FROM inserted
EXEC [dbo].[spCompanyStatusAfterInsert] N'schema', @dataTable
END
GO
【问题讨论】:
为什么你的SP在没有动态语句的情况下使用sp_executesql
?以及为什么 CURSOR
看起来可以通过触发器本身中的基于集合的操作轻松实现。
那实际上不是您的实际 SP 吗?如果是这样,要调试它,我们确实需要查看您的真实代码。如果那是您的实际 SP,那么您的评论无法回答我的问题。
您的逻辑在这里确实存在很大缺陷。你有一个光标,你似乎期望订单。但你没有订单。然后,您通过游标在每次迭代中更新整个表,并有效地撤消您在上次迭代中所做的更改。为什么???这尖叫着糟糕的设计和xy problem。
我建议对您想要的更新进行一次更新比这里的光标更有意义。
也许您最好向我们展示您插入的数据,然后向我们展示您所追求的结果以及原因。
【参考方案1】:
测试一下
CREATE PROCEDURE [dbo].[spCompanyStatusAfterInsert](@schemaName nvarchar(100), @dataTable CompanyStatus READONLY)
AS
BEGIN
DECLARE @sql nvarchar(max)
SELECT @sql = N'
UPDATE tab
SET IsLast = CASE src.id WHEN tab.id THEN 1 ELSE 0 END
FROM ' + QUOTENAME(@schemaName ) + N'.[CompanyStatus] tab
INNER JOIN @dataTable src
ON tab.CompanyId = src.companyId
WHERE tab.id = src.id or tab.IsLast=1
'
EXEC sp_executesql @sql, N'@schemaName nvarchar(100), @dataTable CompanyStatus READONLY', @schemaName, @dataTable
END
【讨论】:
以上是关于插入后触发多次插入后无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章