別のテーブルに挿入された行のテーブルの複数の列を更新するトリガーがあります。
FuelTransactionInfo列に挿入されたレコードは、「情報コード」に基づいてFuelTransactionsの列を更新し、fuelTransactionIdを使用して正しい行を見つけます。レポートを簡単にするために、一部のデータを非正規化しています。
行は、複数の値を使用してfuelTransactionInfo列に挿入できます。例えば。、
INSERT INTO fuelTransactionInfo
(...cols)
VALUES
(...values),
(...values),
(...values);
私の問題は、最初の値のセットのみがトリガーで使用されていることです。行ではなくステートメントでトリガーが起動されることを理解しています。トリガーコードがそれを説明していると思います。しかし、それは単に機能していません。
これが私のトリガーコードです:
ALTER TRIGGER [dbo].[fuelTransactionInfoDev_DenormalizeFuelTransactions]
ON [ERPDev].[dbo].[fuelTransactionInfo]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE t SET
t.employeeNumber = CASE
WHEN fuelInfoCodes.efsCode = 'DRID' THEN
inserted.value
ELSE t.employeeNumber
END,
t.unitNumber = CASE
WHEN fuelInfoCodes.efsCode = 'UNIT' THEN
inserted.value
ELSE t.unitNumber
END,
t.contractId = CASE
WHEN fuelInfoCodes.efsCode = 'CNTN' THEN
(SELECT c.id
FROM pinContract p
JOIN contracts c
ON c.contractNumber = p.ContractNumber
WHERE pin = inserted.value)
ELSE t.contractId
END,
t.contract = CASE
WHEN fuelInfoCodes.efsCode = 'CNTN' THEN
(SELECT c.contractNumber
FROM pinContract p
JOIN contracts c
ON c.contractNumber = p.ContractNumber
WHERE pin = inserted.value)
ELSE t.contract
END,
t.driverName = CASE
WHEN fuelInfoCodes.efsCode = 'NAME' THEN
inserted.value
ELSE t.driverName
END,
t.subFleet = CASE
WHEN fuelInfoCodes.efsCode = 'SSUB' THEN
inserted.value
ELSE t.subFleet
END
FROM fuelTransactions t
JOIN inserted
ON inserted.fuelTransactionid = t.id
JOIN fuelInfoCodes
ON fuelInfoCodes.id = inserted.fuelInfoCodeId;
END
トリガーに次のステートメントを追加して、少しテストを行いました。
SELECT * FROM INSERTED INTO insertedTest
InsertedTestテーブルに期待されるすべての行が表示されます。 UPDATEステートメントを同等の選択(「挿入された」ではなく、挿入されたテストテーブルに基づく)に変換してテストしましたが、すべての結合は適切です。
「UNIT」ケースの列のみが実際にfuelTransactionsで更新されます。これは、トリガーを起動するすべての挿入の最初の行です。
何が悪いのですか?さらに情報が必要な場合はお知らせください。
それが機能しない理由は、結合によって各行が複数回更新されるためですが、各更新では元の値のみが表示され、以前の更新の累積値は表示されません。そのため、更新は実質的に以前の更新をキャンセルしています。 (または、SQLはステートメントごとに1つの行の更新のみを許可します。どちらの方法でも、リソースの使用方法は異なりますが、結果は同じです。)
以下は、迅速かつ適切にフォーマットされていない再現です。
declare @insertedexample table (id INT, codeid int, value varchar(10))
INSERT INTO @insertedexample VALUES
(1,1,'newvalue1'),
(1,2,'newvalue2')
declare @targetexample table (id INT, codeid1value varchar(10), codeid2value varchar(10))
INSERT INTO @targetexample VALUES
(1, 'origvalue1', 'origvalue2')
SELECT * FROM @targetexample
UPDATE t
SET
t.codeid1value = CASE WHEN i.codeid=1 THEN i.value ELSE t.codeid1value END,
t.codeid2value = CASE WHEN i.codeid=2 THEN i.value ELSE t.codeid2value END
FROM @targetexample t
JOIN @insertedexample i on i.id = t.id
SELECT * FROM @targetexample
これを処理するために現時点で私が考えることができる唯一の方法は、動的クエリを作成することです。
アーロンのビューの提案は確かに優れています。ただし、ユーザーがfuelTransactions.idによってのみフィルタリングするか、ピボット後のフィルタリングを処理するためにデータが十分に小さい場合に限られます。 (編集:後でベーステーブルでのインデックスのサポートに依存して、効率的な追加のフィルタリングを可能にするビューまたはビューのセット、または確かに関数を作成することも可能であることに後で気付きました。)
更新:
興味のあるefsCodeコードと同様に、fuelTransactionsテーブルの列が固定されているため、実際にはおそらく動的クエリは必要ありません。
醜いサブクエリの束を使用する必要がある場合でも、更新されていない列の現在の値を組み込んだ、何らかの形式のピボットを使用できる場合があります。
実験する時間があるかもしれませんが、約束することはできません。