简体   繁体   中英

SQL Server : After Insert Trigger for update another Table

I wrote this trigger to insert data into another table after data insert into the CHECKINOUT table.

But it doesn't insert data into the Att_process table. No errors is showing up in SQL Server. Can you help me to figure this out problem?

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TRIGGER [dbo].[trgAfterInsert] ON [dbo].[CHECKINOUT]
AFTER  INSERT 
AS
     DECLARE @uid INT;
     DECLARE @checkin DATETIME;

     SELECT @uid = i.USERID
     FROM [CHECKINOUT] i;

     SELECT @checkin = i.CHECKTIME
     FROM [CHECKINOUT] i;

     IF(DATEPART(HOUR, @checkin) < 12)
     BEGIN
        INSERT INTO Att_process (USERID, checkin_time)
        VALUES (@uid, @checkin);
     END;
     ELSE
     BEGIN
         INSERT INTO Att_process (USERID, checkout_time)
         VALUES (@uid, @checkin);
     END;

Two main problems:

  • you're not looking at the Inserted pseudo table which contains the newly inserted rows

  • you're assuming the trigger is called once per row - this is not the case, the trigger is called once per statement and the Inserted pseudo table will contain multiple rows - and you need to deal with that

So try this code instead:

CREATE TRIGGER [dbo].[trgAfterInsert] ON [dbo].[CHECKINOUT]
AFTER  INSERT 
AS
    -- grab all the rows from the "Inserted" pseudo table
    -- and insert into the "checkin_time" column, if the value
    -- of the HOUR is less than 12
    INSERT INTO Att_process (USERID, checkin_time)
        SELECT  
            i.USERID, i.CHECKTIME
        FROM  
            Inserted i
        WHERE
            DATEPART(HOUR, i.CHECKTIME) < 12

    -- grab all other rows (HOUR is greater than or equal to 12)
    -- and insert into the "checkout_time" column
    INSERT INTO Att_process (USERID, checkout_time)
        SELECT  
            i.USERID, i.CHECKTIME
        FROM  
            Inserted i
        WHERE
            DATEPART(HOUR, i.CHECKTIME) >= 12

As many SQL developers did, you had experienced the same error with SQL Server triggers. You have missed the case when multiple insert statements are executed on the table. Triggers are executed only once for the SQL statement, not for each row. So the code in the trigger should be able to cover all tasks for all rows affected by the SQL statement.

Here is a sample how you can alter your trigger code.

ALTER TRIGGER [dbo].[trgAfterInsert] ON [dbo].[CHECKINOUT]
AFTER  INSERT 
AS

INSERT INTO Att_process (USERID, checkin_time, checkout_time)
select
    USERID, 
    case when DATEPART(HOUR, CHECKTIME) < 12 then CHECKTIME else null end,
    case when DATEPART(HOUR, CHECKTIME) < 12 then null else CHECKTIME end
FROM inserted

For obtaining stable results, please use the Inserted and Deleted internal tables which are available within trigger codes.

You can further check sample SQL Trigger to log changes for how Deleted and Inserted tables are used.

I hope that helps you,

One last note, if you can use SQL Output clause to insert data into two tables at the same time. But of course triggers work on table base, so where ever the insert statement is executed triggers work. If you use Output clause, you should guarantee that the only SQL statement which inserts data into that table will be it to maintain consistency between two tables.

Try this, since you are not using 'inserted' magic table to extract last inserted data.

 DECLARE @uid INT;
 DECLARE @checkin DATETIME;

 SELECT @uid = USERID  FROM inserted   

 SELECT @checkin = CHECKTIME FROM inserted 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM