Insert Trigger

  • Hi,

    May I know how should I write the trigger if I wish to get the inserted record in Table A Server A and insert into Table A Server B?

    Thanks.

  • Here you go...

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_create2_7eeq.asp

    if that doesnt make any sense to you yet, post again, with you table and column names, will assist you gladly.

    regards,

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    This thing is addressing problems that dont exist. Its solution-ism at its worst. We are dumbing down machines that are inherently superior. - Gilfoyle

  • CREATE TRIGGER [tr_Emp] ON [Employee]

    FOR INSERT

    AS

    DECLARE

    @EmpID varchar(20),

    @EmpName varchar(100)

    SELECT @EmpID=INSERTED.EmpID, @EmpName=INSERTED.EmpName

    FROM INSERTED

    BEGIN

    SET NOCOUNT ON;

    IF @EmpID IS NOT NULL

    BEGIN

    INSERT INTO [ServerName].[DBName].[Employee] (EmpID, EmpName)

    VALUES (@EmpID, @EmpName)

    END

    END

    GO

    Is this correct?

  • Okay, I have a couple of comments about your situation.

    1. Don't do it this way. You do not want a trigger to have to do anything outside the database/server it sits on. You are asking for trouble as the trigger takes place within a transaction. If serverB is unavailable then your trigger will cause the transaction to fail. Since you are using SQL Server 2000 (based on the forum you posted in) I would recommend creating a queue table that you insert the rows into using a trigger and then either a SQL Server job or windows service that processes the data in the queue table and inserts into the table on ServerB. You could also look into replication as it might fit your need (I am not a replication expert).

    2. The trigger code you have posted does not handle a set-based insert. So if a set based insert occurs you will not have ALL the rows inserted transferred to the other server.

    I also recommend you read this article, Intoduction to DML Triggers[/url]. Then post any questions you might have either on this thread or the discussion thread of the article.

  • Jack Corbett (11/13/2009)


    Okay, I have a couple of comments about your situation.

    1. Don't do it this way. You do not want a trigger to have to do anything outside the database/server it sits on. You are asking for trouble as the trigger takes place within a transaction. If serverB is unavailable then your trigger will cause the transaction to fail. Since you are using SQL Server 2000 (based on the forum you posted in) I would recommend creating a queue table that you insert the rows into using a trigger and then either a SQL Server job or windows service that processes the data in the queue table and inserts into the table on ServerB. You could also look into replication as it might fit your need (I am not a replication expert).

    2. The trigger code you have posted does not handle a set-based insert. So if a set based insert occurs you will not have ALL the rows inserted transferred to the other server.

    I also recommend you read this article, Intoduction to DML Triggers[/url]. Then post any questions you might have either on this thread or the discussion thread of the article.

    Is SQL Server job means Stored Procedure? Possible to set windows service to process the data in the queue table? Any reference for me?

  • A job could call a stored procedure (my preferred method) or it could just be T-SQL.

    You'd have to write a windows service, probably use .NET, that reads unprocessed rows in the table, transfers them, then marks them as processed. I don't have a specific places where you can see it done. I've just done similar things many times. Sometimes even more complex where we've uses Microsoft Message Queue as well.

    The key is that either of these makes the syncing across servers asynchronous which is what you are looking for. Using a trigger across servers is synchronous so the transaction is made more complex and lengthened, which will hurt concurrency and as mentioned may cause the original transaction to fail, and I don't think you want that.

  • Jack Corbett (11/14/2009)


    A job could call a stored procedure (my preferred method) or it could just be T-SQL.

    You'd have to write a windows service, probably use .NET, that reads unprocessed rows in the table, transfers them, then marks them as processed. I don't have a specific places where you can see it done. I've just done similar things many times. Sometimes even more complex where we've uses Microsoft Message Queue as well.

    The key is that either of these makes the syncing across servers asynchronous which is what you are looking for. Using a trigger across servers is synchronous so the transaction is made more complex and lengthened, which will hurt concurrency and as mentioned may cause the original transaction to fail, and I don't think you want that.

    So means I post the data into table Employee with a flag set to zero. Then I create a stored procedure that get all records with flag = 0 from Employee table and insert into separate server. Then set the stored procedure as a scheduled task right?

  • A simple, T-SQL only process would be something like this (not tested so you may have to make some changes):

    CREATE TABLE EmployeeQueue

    (

    EmpId INT,

    CreatedDate SMALLDATETIME CONSTRAINT DF_EmployeeQueue_CreatedDate DEFAULT GETDATE(),

    ProcessedDate SMALLDATETIME,

    CONSTRAINT PK_EmployeeQueue_EmpID_CreatedDate

    PRIMARY KEY NONCLUSTERED (EmpId, CreatedDate)

    );

    GO

    CREATE TRIGGER tr_Emp_Ins ON Employee

    FOR INSERT

    AS

    SET NOCOUNT ON;

    /* This is now set-based so will handle a set based insert */

    INSERT INTO EmployeeQueue (

    EmpId

    )

    SELECT

    EmpId

    FROM

    inserted;

    GO

    CREATE PROCEDURE EmployeeDataTransfer

    AS

    SET NOCOUNT ON

    DECLARE @emps TABLE (empid INT, createddate);

    /*

    Need this so we only mark the ones transferred as

    processed

    */

    INSERT INTO @emps (

    empid,

    createddate

    )

    SELECT

    EmpId,

    CreatedDate

    FROM

    EmployeeQueue AS EQ

    WHERE

    ProcessedDate IS NULL;

    INSERT INTO LinkedServer.DATABASE.schema.TABLE

    SELECT

    *

    FROM

    @emps AS E JOIN

    Employee AS EQ ON

    E.empid = EQ.EmpId;

    /* Successfully transferred so mark as processed */

    IF @@ERROR = 0

    BEGIN

    UPDATE EmployeeQueue

    SET ProcessedDate = GETDATE()

    WHERE

    EXISTS (SELECT 1 FROM @emps AS E WHERE EmpId = E.empid AND createddate = E.CreatedDate);

    END

  • Jack Corbett (11/16/2009)


    A simple, T-SQL only process would be something like this (not tested so you may have to make some changes):

    CREATE TABLE EmployeeQueue

    (

    EmpId INT,

    CreatedDate SMALLDATETIME CONSTRAINT DF_EmployeeQueue_CreatedDate DEFAULT GETDATE(),

    ProcessedDate SMALLDATETIME,

    CONSTRAINT PK_EmployeeQueue_EmpID_CreatedDate

    PRIMARY KEY NONCLUSTERED (EmpId, CreatedDate)

    );

    GO

    CREATE TRIGGER tr_Emp_Ins ON Employee

    FOR INSERT

    AS

    SET NOCOUNT ON;

    /* This is now set-based so will handle a set based insert */

    INSERT INTO EmployeeQueue (

    EmpId

    )

    SELECT

    EmpId

    FROM

    inserted;

    GO

    CREATE PROCEDURE EmployeeDataTransfer

    AS

    SET NOCOUNT ON

    DECLARE @emps TABLE (empid INT, createddate);

    /*

    Need this so we only mark the ones transferred as

    processed

    */

    INSERT INTO @emps (

    empid,

    createddate

    )

    SELECT

    EmpId,

    CreatedDate

    FROM

    EmployeeQueue AS EQ

    WHERE

    ProcessedDate IS NULL;

    INSERT INTO LinkedServer.DATABASE.schema.TABLE

    SELECT

    *

    FROM

    @emps AS E JOIN

    Employee AS EQ ON

    E.empid = EQ.EmpId;

    /* Successfully transferred so mark as processed */

    IF @@ERROR = 0

    BEGIN

    UPDATE EmployeeQueue

    SET ProcessedDate = GETDATE()

    WHERE

    EXISTS (SELECT 1 FROM @emps AS E WHERE EmpId = E.empid AND createddate = E.CreatedDate);

    END

    Hi, I follow the code provided above and did some modifications, it works fine.

    But just a small part I need clarification:

    /* Successfully transferred so mark as processed */

    IF @@ERROR = 0

    BEGIN

    UPDATE EmployeeQueue

    SET ProcessedDate = GETDATE()

    WHERE

    EXISTS (SELECT 1 FROM @emps AS E WHERE EmpId = E.empid AND createddate = E.CreatedDate);

    END

    This update code will update ALL the ProcessedDate inside the EmployeeQueue, overwrite the ProcessedDate data.

    How to modify just to update the processed batch of records?

    Is it put "WHERE ProcessedDT IS NULL"?

    Please advice. Thanks.

  • Note the WHERE clause on the snippet. I load all the rows with a NULL ProcessedDate into the @emps table variable, process the rows. Then use the table variable to limit the update statement. That's what WHERE EXISTS does.

  • Jack Corbett (11/30/2009)


    Note the WHERE clause on the snippet. I load all the rows with a NULL ProcessedDate into the @emps table variable, process the rows. Then use the table variable to limit the update statement. That's what WHERE EXISTS does.

    DECLARE @emps TABLE (empid INT, createddate);

    /*

    Need this so we only mark the ones transferred as

    processed

    */

    INSERT INTO @emps (

    empid,

    createddate

    )

    SELECT

    EmpId,

    CreatedDate

    FROM

    EmployeeQueue AS EQ

    WHERE

    ProcessedDate IS NULL;

    /*

    Testing Code

    */

    SELECT *

    FROM

    EmployeeQueue

    WHERE

    EXISTS (SELECT 1 FROM @emps AS E WHERE EmpId = E.empid AND createddate = E.CreatedDate);

    I try run the above code in SQL Query Analyzer, it returns all the rows inside the EmployeeQueue table.

  • If you haven't processed any rows yet then all the rows will be returned.

  • Jack Corbett (12/1/2009)


    If you haven't processed any rows yet then all the rows will be returned.

    Hmm... I still not very clear about that.

    A temporarily table "@eps" was created to hold records with NULL ProcessedDate right?

    By right the following query should return records with NULL ProcessedDate right?

    DECLARE @emps TABLE (empid INT, createddate);

    /*

    Need this so we only mark the ones transferred as

    processed

    */

    INSERT INTO @emps (

    empid,

    createddate

    )

    SELECT

    EmpId,

    CreatedDate

    FROM

    EmployeeQueue AS EQ

    WHERE

    ProcessedDate IS NULL;

    /*

    Testing Code

    */

    SELECT *

    FROM

    EmployeeQueue

    WHERE

    EXISTS (SELECT 1 FROM @emps AS E WHERE EmpId = E.empid AND createddate = E.CreatedDate);

    Or I explain in example will be easy to understand:

    Table EmployeeQueue:

    EmpID CreatedDate ProcessedDate

    1 2009-Dec-01 14:00:00 2009-Dec-01 15:00:00

    2 2009-Dec-01 16:00:00 NULL

    After I run the query stated above, it will return me 2 rows of record. By right it should return me the record with NULL ProcessedDate right?

Viewing 13 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic. Login to reply