2017-05-13 5 views
2
CREATE TRIGGER T 
ON TABLE_2 
AFTER INSERT 
AS 
    DECLARE @bought_t int, 
      @name_t varchar(20) 

    SELECT @name_t = name_t 
    FROM inserted 

    SELECT @bought_t = bought_t 
    FROM TABLE_1 
    WHERE name_t = @name_t 

    IF @bought_t < 100 
    BEGIN 
     UPDATE TABLE_1 
     SET bought_t = @bought_t + 1 
     WHERE TABLE_1.name_t = @name_t 
    END 
    ELSE 
     ROLLBACK TRANSACTION 

列(TABLE_1)「TABLE_2」で挿入が行われた後に更新を行っていますが、50と100の間の値を保持するはずです。だから私はこのトリガーがプロとして最適化されているかかもしれない?バグやセキュリティ問題につながる可能性のある欠陥がいくつかあります。トリガーを最適化するには?

+3

あなたのトリガーには、**行ごとに** **と呼ばれる**と思われる**の主な**欠陥があります。トリガは**文ごとに** **起動します。したがって、このトリガを起動させる 'INSERT'文が25行挿入された場合、トリガは一度**発生しますが、' Inserted'擬似テーブルは25行あります。あなたのコードがここで選択する25行のうちどれですか? 'SELECT @name_t = name_t FROM inserted' - 非決定論的ですが、**任意の行**を取得し、**すべての他の行を無視します**。これを考慮に入れてトリガーを書き直す必要があります。 –

+0

これはトランザクション内にあることをどのように知っていますか? 'else into rollback'を使用すると、' insert into' TABLE_2がトランザクションで開始しなかったときに、トリガーが 'rollback'コードを実行するとエラーがスローされます。また、どのようなものがロールバックされるのかをどうやって知っていますか?他の誰かがコードを書いた場合、 'bought_t 'の値が> = 100のときに変更がロールバックされる理由を理解できますか?さらに多くの情報を必要とせずに最適化されているかどうかは言えません。まず、SSMSのトリガから 'update'文を実行し、クエリプランを取得するだけです。それはあなたに多くを伝えるべきです。 –

+0

@marc_s確かに。 (A、B)、 ( 'B'、 'Z')、 ( 'S'、 'A')、 ( 'A'、 'B' '、' S ')、 (' D '、' G ')' と私は一度だけ実行している更新機能を持っています。 @ JamesL。 – user3832856

答えて

1

基本的に、あなたは完全にセットベースのするとInserted擬似テーブルに複数行で作業できるようにするには、あなたのトリガーを書き換える必要があります。

CREATE TRIGGER T 
ON TABLE_2 
AFTER INSERT 
AS 
    UPDATE T1 
    SET bought_t = bought_t + 1 
    FROM TABLE_1 T1 
    INNER JOIN Inserted i ON i.name_t = T1.name_t 
    WHERE T1.bought_t < 100 

がUPDATE::この作品を証明するデモ:

-- create the two tables 
CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50)) 
CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT) 
GO 

-- create trigger on "TABLE_2" to update "TABLE_1"  
CREATE TRIGGER T2Insert 
ON TABLE_2 
AFTER INSERT 
AS 
    UPDATE T1 
    SET Bought = Bought + 1 
    FROM TABLE_1 T1 
    INNER JOIN Inserted i ON T1.ProdName = i.ProdName 
    WHERE T1.Bought < 100 
GO 

-- initialize TABLE_1 with some seed data 
INSERT INTO dbo.TABLE_1 (ProdName, Bought) 
VALUES ('Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100) 

-- insert new values into TABLE_2 
INSERT INTO dbo.TABLE_2 (ProdName) 
VALUES ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4') 

-- get data to check 
SELECT * FROM dbo.TABLE_1 

これは、出力をレンダリング:

- 私の意見では - このような何かをしようともそれが容易になり幸い

enter image description here

簡単に見ることができるように:挿入された

  • PROD1、PROD2、Prod4も挿入されたBought
  • Prod100がない原因Bought
の更新をした値の更新を引き起こしました

UPDATE#2:同じ値を複数同時に挿入する必要がある場合は、次のようにトリガーを少し強化する必要があります。

+0

'@ buy_t'を単に' bought_t'にしてはいけませんか? –

+0

@JamesL .:はい - もちろん、コピー&ペーストのエラー - 固定、ありがとう! –

+0

これはまだ更新を1回だけ行うことになります。上記のコメントに与えられた値を挿入すると、 '(1行が影響を受ける) (5行が影響を受ける)'トリガーは5の代わりに1回だけ更新されます – user3832856