我正在开发一个电子商务系统,我有一个订单表,存储有关订单的所有信息。订单经历了不同的阶段:开放,验证,进行中等。我在不同的阶段保持这些订单的数量,例如未完成订单95,已验证5,正在处理3等
当在表中插入新订单时,我有一个触发器,将未结订单递增1.同样,我有一个更新触发器,它检查订单的前一阶段,然后下一个递减并相应地递增。
如上所述,INSERT触发器正常工作。但是UPDATE触发器有一种奇怪的行为,它会对Counts进行所需的更改,但由于某种原因会反转这些更改。
例如,在将订单状态从“打开”更改为“已验证”时,理想的行为是将“未结订单”减少1并将“验证订单”增加1.触发器当前执行了所需的操作,但由于某种原因,还原以前的价值。
这是我的触发片段,我在此检查订单以前是否属于未结状态,现在正在更新为已验证状态:
IF @@ROWCOUNT = 0 RETURN
DECLARE @orderID VARCHAR(MAX) -- orderID of the order that is being updated
DECLARE @storeID VARCHAR(MAX) -- storeID of the store the order belongs to
SELECT TOP 1
@orderID = i.id,
@storeID = i.storeID
FROM
inserted AS i
INNER JOIN deleted AS d
ON i.id = d.id
-- IF from Open Order
IF EXISTS (
SELECT *
FROM
deleted
WHERE
orderStatus = 'Open' AND
id = @orderID
)
BEGIN
-- IF to Verified Order
IF EXISTS (
SELECT *
FROM
inserted
WHERE
orderStatus = 'Verified' AND
id = @orderID
)
BEGIN
UPDATE order_counts
SET
open_orders = open_orders - @@ROWCOUNT,
verified_orders = verified_orders + @@ROWCOUNT
WHERE storeID = @storeID
END
END
修改:
这里有一些额外的信息,根据对问题的第一条评论会有所帮助:
我在表中有很多记录,因此一次又一次地使用COUNT()
会对整体性能产生很大影响。这就是为什么我把计数保存在一个单独的表中。此外,我以一种处理单个记录/多记录更改的方式编写了触发器。我只检查一行,因为我知道如果有多个记录,他们都会经历相同的状态变化。因此,@@ROWCOUNT
答案 0 :(得分:0)
如果你能容忍略微不同的订单计数表示,我强烈建议使用indexed view代替 1 :
create table dbo.Orders (
ID int not null,
OrderStatus varchar(20) not null,
constraint PK_Orders PRIMARY KEY (ID)
)
go
create view dbo.OrderCounts
with schemabinding
as
select
OrderStatus,
COUNT_BIG(*) as Cnt
from
dbo.Orders
group by OrderStatus
go
create unique clustered index IX_OrderCounts on dbo.OrderCounts (OrderStatus)
go
insert into dbo.Orders (ID,OrderStatus) values
(1,'Open'),
(2,'Open'),
(3,'Verified')
go
update dbo.Orders set OrderStatus = 'Verified' where ID = 2
go
select * from dbo.OrderCounts
结果:
OrderStatus Cnt
-------------------- --------------------
Open 1
Verified 2
这样做的好处是,虽然SQL Server正在执行与运行触发器非常相似的操作,但此代码已经过彻底调试并且是正确的。
在当前尝试的触发器中,触发器当前被破坏的另一个原因是@@ROWCOUNT
不是“粘性” - 它不记得受原始{{1}影响的行数当你在触发器中运行其他语句时也会设置UPDATE
。
1 您始终可以在此视图的顶部堆叠非索引视图,如果您真的想要计算单行和多列中的计数,则执行@@ROWCOUNT
。
答案 1 :(得分:0)
这种行为的原因是多次使用@@ ROWCOUNT,而实际上一旦获取@@ ROWCOUNT的结果,结果就会被清除。而是将结果变为变量并在触发器中使用该变量。检查以下方案是否相同。
CREATE DATABASE Test
USE Test
CREATE TABLE One
(
ID INT IDENTITY(1,1)
,Name NVARCHAR(MAX)
)
GO
CREATE TRIGGER TR_One ON One FOR INSERT,UPDATE
AS
BEGIN
PRINT @@ROWCOUNT
SELECT @@ROWCOUNT
END
UPDATE One
SET Name = 'Name4'
WHERE ID = 3
结果: -
Print @@ ROWCOUNT语句的值为1,其中select @@ ROWCOUNT的值为0