2017-11-24 27 views
0

これは私を困惑させます。顧客テーブルの残高を更新するAFTER INSERTトリガを持つトランザクションテーブルがあります。単一の顧客のために、挿入された仮想テーブル内の複数の行でトリガーが起動することは、まったく正常です。SQL Serverの後に挿入2番目のテーブルを挿入ごとに複数回更新するトリガー

例:

顧客の残高が500

INSERTは、顧客のために複数の行を生成するトランザクションテーブルに作ら最初の行は50借方であり、第二は100借方です。

トリガ後の予想結果は顧客残高350です。実際の結果は450です。前回の行が更新された後の残高ではなく、顧客に対するトリガの結合が毎回同じ残高を返すように見えます。

CREATE TRIGGER [dbo].[tBalances] 
ON [dbo].[tblCustomerTransaction] 
AFTER INSERT 
AS 
BEGIN 
    IF @@ROWCOUNT = 0 RETURN 
    SET NOCOUNT ON; 

    UPDATE C 
    SET  C.AvailableBalance = C.AvailableBalance + CASE WHEN TT.bIsDebit = 1 THEN I.decAmount * -1 ELSE I.decAmount END, 
      C.BonusBalance = C.BonusBalance + CASE WHEN TT.bIsDebit = 1 THEN I.decBonusAmount * -1 ELSE I.decBonusAmount END 
    FROM inserted AS I 
      INNER JOIN tblCustomer AS C ON I.iCustomerID = C.CustomerId   
      INNER JOIN tblTransactionType AS TT ON I.iTransactionTypeID = TT.iTransactionTypeID   
    WHERE I.iManagerID = 12345 
END 

はなぜ:

挿入#1は 、インサート#2が500ない450のバランスをとり、ここで

から100控除トリガーだ500のバランスを取り、それから50差し引き顧客表の更新は、挿入の各行に固執しませんか?

+0

2つの理念(正確に右でない場合は、これはあなたの本当のクエリに適用されるか、うまくいけば、あなたが見ることができる):1)SQL Serverのトリガーは常に文レベル2)全てのアットワンス – lad2025

+0

原則 'UPDATE's (および他のDML)は、*すべての行が同時に影響を受けるかのように動作します*。考慮する「前の行」はありません。これらの集計を自動的に*維持するために索引ビューを使用するだけではない理由はありますか? –

+0

わかりました。この問題の解決策は何ですか?カーソルループではありませんか? – IntoNET

答えて

1

手動でこれらの集計を計算しを持っている(というだけでインデックス付きビューを定義し、SQL Serverは自動的にそれらを維持させるよりも)、各ターゲット列は単一の更新のみが対象となっていることを確認し場合 - 使用してグループ化:

UPDATE C 
SET  C.AvailableBalance = C.AvailableBalance + BalanceChange, 
     C.BonusBalance = C.BonusBalance + BonusChange 
FROM (SELECT iCustomerID, 
      SUM(CASE WHEN TT.bIsDebit = 1 THEN I.decAmount * -1 
             ELSE I.decAmount END) 
      as BalanceChange, 
      SUM(CASE WHEN TT.bIsDebit = 1 THEN I.decBonusAmount * -1 
             ELSE I.decBonusAmount END) 
      as BonusChange 
     FROM inserted AS I 
     INNER JOIN tblTransactionType AS TT ON I.iTransactionTypeID = TT.iTransactionTypeID 
     WHERE I.iManagerID = 12345 
     GROUP BY iCustomerID) t 
INNER JOIN tblCustomer AS C ON t.iCustomerID = C.CustomerId 

+0

インデックスビューを定義すると、すべての顧客トランザクションからのオンザフライでの残高を計算するビューを顧客テーブルに作成することを意味しますか? – IntoNET

+0

@IntoNET - [Indexed Views](https://docs.microsoft.com/en-us/sql/relational-databases/views/create-indexed-views) - 基本的に、ビューの*結果*はSQL Serverを使用しており、トリガーのようなものを使用して、ベーステーブルの変更に基づいて結果を更新します(トリガーのようなコードがテストされ、使用された回数は何百万回もあります)。 –

+0

ありがとうございました。私の問題は短期間で解決しますが、私はインデックス付きのビューの考え方も見ていきます。 – IntoNET

関連する問題