2017-10-03 49 views
0

レコードが特定の条件に一致する場合、レコードをあるテーブルから同じレプリカテーブルに移動するSQL Serverトリガーを作成したいと考えています。挿入と更新時にSQL Serverトリガー

質問:各列を指定する必要がありますか、またはワイルドカードを使用できますか?

SET @RecID = (SELECT [RecoID] FROM Inserted) 

IF NULLIF(@RecID, '') IS NOT NULL 
    (then insert....) 

THANKS:

は、私は次のようなものを使用することができます!

答えて

1

トリガーで「する」ことができるたくさんのものがありますが、そうする必要はありません。私は、すべてのコストでトリガー内のスカラー変数を設定することを避けることを強く勧めます。たとえあなたのテーブルがアプリケーションごとに1行挿入されることは決してありませんが、それはアプリケーションがどのように設計されているかによって決まります...すべてのトランザクションがアプリケーションを経由するわけではないことがわかった場合、あなたは非常に失礼です。

以下のトリガーの両方のタイプの簡単なデモがある...

USE tempdb; 
GO 

IF OBJECT_ID('tempdb.dbo.PrimaryTable', 'U') IS NOT NULL 
DROP TABLE dbo.PrimaryTable; 
GO 
IF OBJECT_ID('tempdb.dbo.TriggerScalarLog', 'U') IS NOT NULL 
DROP TABLE dbo.TriggerScalarLog; 
GO 
IF OBJECT_ID('tempdb.dbo.TriggerMultiRowLog', 'U') IS NOT NULL 
DROP TABLE dbo.TriggerMultiRowLog; 
GO 

CREATE TABLE dbo.PrimaryTable (
    Pt_ID INT NOT NULL IDENTITY (1,1) PRIMARY KEY CLUSTERED, 
    Col_1 INT NULL, 
    Col_2 DATE NOT NULL 
     CONSTRAINT df_Col2 DEFAULT (GETDATE()) 
    ); 
GO 
CREATE TABLE dbo.TriggerScalarLog (
    Pt_ID INT, 
    Col1_Old INT, 
    Col1_New INT, 
    Col2_Old DATE, 
    Col2_New DATE 
    ); 
GO 
CREATE TABLE dbo.TriggerMultiRowLog (
    Pt_ID INT, 
    Col1_Old INT, 
    Col1_New INT, 
    Col2_Old DATE, 
    Col2_New DATE 
    ); 
GO 

--======================================================= 

CREATE TRIGGER dbo.PrimaryCrudScalar ON dbo.PrimaryTable 
AFTER INSERT, UPDATE, DELETE 
AS 
    SET NOCOUNT ON; 
    DECLARE 
     @Pt_ID INT, 
     @Col1_Old INT, 
     @Col1_New INT, 
     @Col2_Old DATE, 
     @Col2_New DATE; 

    SELECT 
     @Pt_ID = ISNULL(i.Pt_ID, d.Pt_ID), 
     @Col1_Old = d.Col_1, 
     @Col1_New = i.Col_1, 
     @Col2_Old = d.Col_2, 
     @Col2_New = i.Col_2 
    FROM 
     Inserted i 
     FULL JOIN Deleted d 
      ON i.Pt_ID = d.Pt_ID; 

    INSERT dbo.TriggerScalarLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New) 
    VALUES (@Pt_ID, @Col1_Old, @Col1_New, @Col2_Old, @Col2_New); 
GO -- DROP TRIGGER dbo.PrimaryCrudScalar; 

CREATE TRIGGER PrimaryCrudMultiRow ON dbo.PrimaryTable 
AFTER INSERT, UPDATE, DELETE 
AS 
    SET NOCOUNT ON; 

    INSERT dbo.TriggerMultiRowLog (Pt_ID, Col1_Old, Col1_New, Col2_Old, Col2_New) 
    SELECT 
     ISNULL(i.Pt_ID, d.Pt_ID), 
     d.Col_1, 
     i.Col_1, 
     d.Col_2, 
     i.Col_2 
    FROM 
     Inserted i 
     FULL JOIN Deleted d 
      ON i.Pt_ID = d.Pt_ID; 
GO -- DROP TRIGGER dbo.TriggerMultiRowLog; 

--======================================================= 
--======================================================= 

-- --insert test... 
INSERT dbo.PrimaryTable (Col_1) 
SELECT TOP 100 
    o.object_id 
FROM 
    sys.objects o; 

SELECT 'INSERT Scarar results'; 
SELECT * FROM dbo.TriggerScalarLog tsl; 
SELECT 'INSERT Multi-Row results'; 
SELECT * FROM dbo.TriggerMultiRowLog tmrl; 

UPDATE pt SET 
    pt.Col_1 = pt.Col_1 + rv.RandomVal, 
    pt.Col_2 = DATEADD(DAY, rv.RandomVal, pt.Col_2) 
FROM 
    dbo.PrimaryTable pt 
    CROSS APPLY (VALUES (ABS(CHECKSUM(NEWID())) % 10000 + 1)) rv (RandomVal); 

SELECT 'UPDATE Scarar results'; 
SELECT * FROM dbo.TriggerScalarLog tsl; 
SELECT 'UPDATE Multi-Row results'; 
SELECT * FROM dbo.TriggerMultiRowLog tmrl; 

DELETE pt 
FROM 
    dbo.PrimaryTable pt; 

SELECT 'DELETE Scarar results'; 
SELECT * FROM dbo.TriggerScalarLog tsl; 
SELECT 'DELETE Multi-Row results'; 
SELECT * FROM dbo.TriggerMultiRowLog tmrl; 
+0

スカラーオプションを使用すると、単にレコードを移動するだけで、ソーステーブルに残る必要はありません。また、ISNULL(i.Pt_ID、d.Pt_ID)について説明してください。 – user3255066

+0

私はスカラーオプションをこれまでどおりに使用しません。ソーステーブルからDELETEしたい場合は、トリガーではなくストアドプロシージャで処理します。 1つのテーブルでの特別な保守によって意図しない別のデータの削除が発生する可能性はありません。実際には、トリガの使用を主張するユースケースはごくわずかです...監査履歴の管理や、2つの異なる環境で2つのテーブルが互いに同期していることを確認することなどがあります。それはそれです。 –

+0

ISNULL(i.Pt_ID、d.Pt_ID)... UPDATE文は2つのテーブルを生成します(Inserted&Deleted)...私の例では、IDごとに1つの監査行を生成したかったので、挿入されたIDと削除されたID(FULL JOIN Deleted d ON i.Pt_ID = d.Pt_ID)とISNULL(i.Pt_ID、d.Pt_ID)の完全結合は、単に "INSERTの場合はi.Pt_IDこれがDELETEであれば、d.Pt_IDを使用してください。これがUPDATEの場合は、同じ値なのでどちらを気にしなくてもかまいません。 –

0

私はそれに反対することもできます。あなたのソーステーブルが変更された場合、失敗することになります。

また、一度に複数の行を挿入する場合は、エラーがスローされる(または予期しない結果が生じる)場合もあります。

INSERT table2 ( user_id , 
       user_name , 
       RecoID 
     ) 
    SELECT user_id , 
      user_name , 
      RecoID 
    FROM inserted i 
      LEFT JOIN table2 t ON i.RecoID = t.RecoID 
    WHERE t.RecoID IS NULL; 

EDIT:

あなたは、元のテーブルの上に起こって挿入を停止する場合は、あなたはの線に沿って何かをする必要があります:

私はより多くのセットベースのアプローチをお勧めします
CREATE TRIGGER trigger_name 
ON table_orig 
INSTEAD OF INSERT 
AS 
    BEGIN 

    -- make sure we aren't triggering from ourselves from another trigger 
    IF TRIGGER_NESTLEVEL() <= 1 
     return; 

     -- insert into the table_copy if the inserted row is already in table_orig (not null) 
     INSERT table_copy ( user_id , 
           user_name , 
           RecoID 
         ) 
      SELECT user_id , 
        user_name , 
        RecoID 
      FROM inserted i 
        LEFT JOIN table_orig c ON i.RecoID = c.RecoID 
      WHERE t.RecoID IS NOT NULL; 

     -- insert into table_orig if the inserted row is not already in table_orig (null) 
     INSERT table_orig ( user_id , 
           user_name , 
           RecoID 
         ) 
       SELECT user_id , 
         user_name , 
         RecoID 
       FROM inserted i 
         LEFT JOIN table_orig c ON i.RecoID = c.RecoID 
       WHERE t.RecoID IS NULL; 
    END; 

instead ofは、実際に挿入したくない場合は挿入を停止するので、自分で行う必要があります(2番目の挿入文)。

ご了承ください。nullsnot nullsに変更する場合があります。

+0

アイデアは動きがレコードを移動している場合は、LEFT JOINのが必要なのですか?挿入された\更新されたレコードを削除することをどのようにお勧めしますか? – user3255066

+0

@ user3255066答えが更新されました – LordBaconPants

関連する問題