此过程有几个步骤,这些步骤反射(reflect)在数据库的各个表中:
生产 --> 更新
到库存表,使用类似
UPDATE STOR SET
STOR.BLOC1 = T.BLOC1,
STOR.BLOC2 = T.BLOC2,
STOR.BLOC3 = T.BLOC3,
STOR.PRODUCTION = T.PROD,
STOR.DELTA = T.DELTA
FROM BLDG B INNER JOIN STOR S
ON S.B_ID = B.B_ID
CROSS APPLY dbo.INVENTORIZE(B.B_ID) AS T;
上面使用 TRIGGER
提供日志表,如下所示:
CREATE TRIGGER trgrCYCLE
ON STOR
FOR UPDATE
AS
INSERT INTO dbo.INVT
(TS, BLDG, PROD, ACT, VAL)
SELECT CURRENT_TIMESTAMP, B_ID, PRODUCTION,
CASE WHEN DELTA < 0 THEN 'SELL' ELSE 'BUY' END,
DELTA
FROM inserted WHERE COALESCE(DELTA,0) <> 0
最后,每次更新都应该 插入
一行到我添加到上面触发器的财务表中:
INSERT INTO dbo.FINS
(COMPANY, TS, COST2, BAL)
SELECT CORP, CURRENT_TIMESTAMP, COST,
((SELECT TOP 1 BAL FROM FINS WHERE COMPANY = CORP ORDER BY TS DESC)- COST)
FROM inserted WHERE COALESCE(COST,0) <> 0
问题出在这一行:
((SELECT TOP 1 BAL FROM FINS WHERE COMPANY = CORP ORDER BY TS DESC)- COST)
用于计算帐户的最新余额。但是,由于CROSS APPLY
将所有INSERTS
视为一批,因此计算是根据同一条最后记录完成的,并且我得到的余额数字不正确。示例:
COST BALANCE
----------------
1,000 <-- initial balance
-150 850
-220 780 <-- should be 630
有什么方法可以解决这个问题?在 FINS
表上使用触发器来代替余额计算?
最佳答案
了解查询中的现有逻辑
UPDATE
语句只会针对满足连接条件的集合或批处理触发一次触发器
,Inserted 语句将包含正在更新的所有记录。这是因为 BATCH 处理不是因为 CROSS APPLY
而是因为 UPDATE
。
在您的这个查询中
SELECT CORP, CURRENT_TIMESTAMP, COST,
((SELECT TOP 1 BAL FROM FINS WHERE COMPANY = CORP ORDER BY TS DESC)- COST)
FROM inserted WHERE COALESCE(COST,0) <> 0
对于来自外部查询的每个 CORP,将返回相同的 BAL。
(SELECT TOP 1 BAL FROM FINS WHERE COMPANY = CORP ORDER BY TS DESC)
话虽这么说,每次 CORP = 'XYZ' 时,您的内部查询都会被替换为 1000(您在示例中使用的值)
SELECT CORP, CURRENT_TIMESTAMP, COST, (1000- COST)
FROM inserted WHERE COALESCE(COST,0) <> 0
现在您的插入语句包含了正在插入的所有记录。因此每条记录的成本都会减去 1000。因此您会得到意想不到的结果。
建议的解决方案
根据我的理解,你想要计算一些累积频率之类的东西。或上次运行总计
问题陈述的数据准备。使用我的虚拟数据给您一个想法。
--Sort data based on timestamp in desc order
SELECT PK_LoginId AS Bal, FK_RoleId AS Cost, AddedDate AS TS
, ROW_NUMBER() OVER (ORDER BY AddedDate DESC) AS Rno
INTO ##tmp
FROM dbo.M_Login WHERE AddedDate IS NOT NULL
--Check how data looks
SELECT Bal, Cost, Rno, TS FROM ##tmp
--Considering ##tmp as your inserted table,
--I just added Row_Number to apply Top 1 Order by desc logic
+-----+------+-----+-------------------------+
| Bal | Cost | Rno | TS |
+-----+------+-----+-------------------------+
| 172 | 10 | 1 | 2012-12-05 08:16:28.767 |
| 171 | 10 | 2 | 2012-12-04 14:36:36.483 |
| 169 | 12 | 3 | 2012-12-04 14:34:36.173 |
| 168 | 12 | 4 | 2012-12-04 14:33:37.127 |
| 167 | 10 | 5 | 2012-12-04 14:31:21.593 |
| 166 | 15 | 6 | 2012-12-04 14:30:36.360 |
+-----+------+-----+-------------------------+
从上次运行余额中减去成本的替代逻辑。
--Start a recursive query to subtract balance based on cost
;WITH cte(Bal, Cost, Rno)
AS
(
SELECT t.Bal, 0, t.Rno FROM ##tmp t WHERE t.Rno = 1
UNION ALL
SELECT c.Bal - t.Cost, t.Cost, t.Rno FROM ##tmp t
INNER JOIN cte c ON t.RNo - 1 = c.Rno
)
SELECT * INTO ##Fin FROM cte;
SELECT * FROM ##Fin
输出
+-----+------+-----+
| Bal | Cost | Rno |
+-----+------+-----+
| 172 | 0 | 1 |
| 162 | 10 | 2 |
| 150 | 12 | 3 |
| 138 | 12 | 4 |
| 128 | 10 | 5 |
| 113 | 15 | 6 |
+-----+------+-----+
您必须在您的专栏上发布一点推文才能将此功能纳入您的触发器中。
关于sql-server - 由 CROSS APPLY 触发时的顺序 SQL 插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21893462/