[英]Trigger to update balance after a transaction amount record has been changed
Tables account and transactions表帐户和交易
Account = {accNumber, type, balance, rate, branchName}
Transaction = {accNumber, transNumber, amount, transDate, description}
I have managed to create trigger to update balance after INSERT我已经设法在插入后创建触发器来更新余额
CREATE TRIGGER TR_Account_Balance
ON Transactions AFTER INSERT
AS
BEGIN
UPDATE account SET
balance = ins.newBalance
FROM (
SELECT a.accnumber,a.balance + SUM(i.amount) AS newBalance
FROM Account a
INNER JOIN inserted i ON i.accNumber = a.accNumber
GROUP BY a.accNumber, a.balance
) AS ins
WHERE account.accnumber = ins.accnumber
END
Now I need to create a trigger that would change balance accordingly to transaction AFTER UPDATE.现在我需要创建一个触发器,该触发器将根据事务更新后相应地更改余额。
How can I possibly do that?我怎么可能做到这一点?
You should really do this in a normalized fashion, by using a view.您应该通过使用视图以规范化的方式真正做到这一点。 For better performance, you can index it.
为了获得更好的性能,您可以对其进行索引。
Indexed views are subject to some restrictions, in particular:索引视图受到一些限制,特别是:
COUNT_BIG
and can only use SUM
as another aggregateCOUNT_BIG
并且只能将SUM
用作另一个聚合CREATE VIEW dbo.vAccountBalance
WITH SCHEMABINDING AS
SELECT
tr.accnumber,
SUM(tr.amount) AS balance,
COUNT_BIG(*) AS numTransactions -- this MUST be added
FROM dbo.Transactions tr; -- schema-qualify
GO
CREATE UNIQUE CLUSTERED INDEX CX_vAccountBalance ON dbo.vAccountBalance (accnumber);
The server will maintain this index together with other indexes, during any insert, update or delete.在任何插入、更新或删除期间,服务器将与其他索引一起维护此索引。
If you really wanted to do this in a trigger, you can use the following如果您真的想在触发器中执行此操作,可以使用以下
Account
table is only referenced once, and the difference is added, rather than self-joining againAccount
表是如何只引用一次的,加了区别,而不是再次自加入inserted
and deleted
are joined together by primary key, and the difference is summedinserted
和deleted
是如何通过主键连接在一起的,差值相加CREATE TRIGGER TR_Account_Balance
ON Transactions AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1 FROM inserted) AND NOT EXISTS (SELECT 1 FROM deleted)
RETURN; -- early bail-out
UPDATE a -- update the already referenced Account table
SET
balance += ins.diffBalance
FROM Account a
INNER JOIN (
SELECT
i.accnumber,
SUM(i.amount) AS diffBalance
FROM (
SELECT i.transNumber, i.accnumber, i.amount
FROM inserted i
)
FULL JOIN (
SELECT d.transNumber, d.accnumber, -(d.amount)
FROM deleted d
) ON i.transNumber = a.transNumber
GROUP BY i.accNumber
) AS ins ON a.accnumber = ins.accnumber;
GO
You could also split this up into separate INSERT
UPDATE
and DELETE
triggers, in which case you can remove the deleted
section for the former, remove the inserted
section for the latter, and change the UPDATE
one to use an INNER JOIN
instead of a FULL JOIN
.您还可以将其拆分为单独的
INSERT
UPDATE
和DELETE
触发器,在这种情况下,您可以删除前者的deleted
部分,删除后者的inserted
部分,并将UPDATE
更改为使用INNER JOIN
而不是FULL JOIN
.
If you do the insert update delete via a proc that will be the best place to update the mapped table or other tables as well.如果您通过 proc 执行插入更新删除,这将是更新映射表或其他表的最佳位置。 If you still want to do it in a trigger (Carefully) please compute your SUM at same table level and update the balance on main table so it'll cover update and delete as well.
如果您仍想在触发器中执行此操作(仔细),请在同一表级别计算您的 SUM 并更新主表上的余额,以便它也涵盖更新和删除。
Schema:架构:
DROP TABLE IF EXISTS dbo.AccountTransaction
DROP TABLE IF EXISTS dbo.Account
CREATE TABLE dbo.Account
(
AccountNumber INT CONSTRAINT PK_AccountId PRIMARY KEY CLUSTERED IDENTITY(1, 1) NOT NULL,
Balance DECIMAL(18, 9) CONSTRAINT DF_Account_Balance DEFAULT 0.0 NOT NULL
)
GO
INSERT INTO dbo.Account
(
Balance
)
VALUES
(
DEFAULT -- decimal(18, 9)
)
CREATE TABLE dbo.AccountTransaction
(
AccountTransactionId INT CONSTRAINT PK_AccountTransactionId PRIMARY KEY CLUSTERED IDENTITY(1, 1) NOT NULL,
AccountNumber INT CONSTRAINT FK_AccountTransaction_Account FOREIGN KEY REFERENCES dbo.Account (AccountNumber) NOT NULL,
Amount DECIMAL(18, 9) CONSTRAINT DF_AccountTransaction_Amount DEFAULT 0.0 NOT NULL
)
GO
CREATE TRIGGER dbo.tr_AccountTransaction
ON dbo.AccountTransaction
FOR INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Account
SET Balance = x.NewBalance
FROM
(
SELECT SUM (at.Amount) AS NewBalance
FROM Inserted AS i
JOIN dbo.AccountTransaction AS at
ON at.AccountNumber = i.AccountNumber
GROUP BY i.AccountNumber
) AS x
END
GO
Testing:测试:
INSERT INTO dbo.AccountTransaction
(
AccountNumber,
Amount
)
SELECT a.AccountNumber,
12.0
FROM dbo.Account AS a
SELECT a.AccountNumber,
a.Balance
FROM dbo.Account AS a
UPDATE at
SET at.Amount += 30
FROM dbo.AccountTransaction AS at
WHERE at.AccountTransactionId = 1
SELECT a.AccountNumber,
a.Balance
FROM dbo.Account AS a
SELECT * FROM dbo.AccountTransaction AS at
DELETE a
FROM dbo.AccountTransaction AS a
WHERE a.AccountTransactionId = 2
SELECT a.AccountNumber,
a.Balance
FROM dbo.Account AS a
SELECT * FROM dbo.AccountTransaction AS at
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.