Trigger Change

  • I have been asked to change an existing trigger to look at the Action Plan column, and if it has changed, update the Action Plan Change Tracking Date/time. (this starts out as NULL) I have not worked on triggers in the past, but the code for this one just feels wrong, first for the insert into the tracking table there is no matching of the mult-column PK between the inserted data and the read data... isn't that a requirement for a trigger to always work correctly? (like has been done in the second part of the trigger)

    The trigger does two things: First it writes the record to a change history table so the last changes can then be written back after the table is truncated and new data loaded. Second it updates some fields, in the updated table.

    I am going to give a much reduced trigger (not as many columns), to try and make this question easier to answer.

    The change I need to make, I have started using the version is V001.007.

    ALTER TRIGGER [dbo].[Log_Details] ON [dbo].[ztb_Details] FOR UPDATE

    AS

    BEGIN

    INSERT INTO ztb_Details_Comment_Hist

    ( Period

    , [Plant-Material]

    , [Batch_Num]

    , [Explanation]

    , [Reserve_Value]

    , [Last_Update_User]

    , [Last_Update_DT]

    , [Action_Plan]

    , Action_Category_Change_DT ---** V001.007

    )

    SELECT cast(Period as date) as Period_DM---** V001.004

    , [Plant-Material]

    , [Batch_Num]

    , [Reserve_Pct]

    , [Explanation]

    , [Tot_Value_Inv_Group] * [Reserve_Pct] as [Reserve_Value]

    , ( SELECT ISNULL(FirstName+ ' '+ Lastname, System_User)

    FROM dbo. WHERE LoginName = System_User) as [Last_Update_User]

    , CURRENT_TIMESTAMP as [Last_Update_DT]

    ---** V001.005 End

    , Action_Plan

    ---** V001.007 Begin

    , Action_Category_Change_DT

    --- ---** V001.007 End

    FROM inserted

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

    UPDATE A

    SET

    Last_Update_DT = CURRENT_TIMESTAMP

    , Last_Update_User = ( SELECT ISNULL(FirstName+ ' '+ Lastname, System_User)

    FROM dbo. WHERE LoginName = System_User)

    , Reserve_Value = b.[Tot_Value_Inv_Group] * b.[Reserve_Pct]

    ---** V001.007 Begin

    , Action_Category_Change_DT = b.Action_Category_Change_DT

    --- ---** V001.007 End

    FROM ztb_Details A

    INNER JOIN inserted B

    on a.[plant-material] = b.[plant-material]

    and a.[batch_num] = b.[batch_num]

    and a.[Period] = b.[Period]

    END

    CREATE TABLE [dbo].[ztb_Details_Comment_Hist](

    [id] [int] IDENTITY(1,1) NOT NULL,

    [Period] [date](250) NOT NULL,

    [Plant-Material] [char](12) NOT NULL,

    [Batch_Num] [varchar](20) NOT NULL,

    [Explanation] [varchar](1000) NULL,

    [Reserve_Value] [float] NULL,

    [Last_Update_User] [varchar](200) NULL,

    [Last_Update_DT] [datetime] NOT NULL,

    [Action_Plan] [varchar](1000) NULL,

    [Action_Category_Change_DT] [datetime] NULL,

    CONSTRAINT [PK_ztb_Details_Comment_Hist] PRIMARY KEY CLUSTERED

    (

    [id] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    ) ON [PRIMARY]

    GO

    CREATE TABLE [dbo].[ztb_Details](

    [Period] [datetime] NOT NULL,

    [Material_CD] [char](6) NOT NULL,

    [Plant_CD] [char](3) NOT NULL,

    [Batch_Num] [varchar](20) NOT NULL,

    [Customer] [varchar](100) NOT NULL,

    [Reserve_Pct] [float] NULL,

    [Tot_Value_Inv_Group] [float] NULL,

    [Reserve_Value] [float] NULL,

    [Action_Plan] [varchar](1000) NULL,

    [Plant-Material] [char](12) NOT NULL,

    [Action_Category_Change_DT] [datetime] NULL,

    [Loaded_From] [varchar](50) NOT NULL,

    CONSTRAINT [PK_ztb_Details_1] PRIMARY KEY CLUSTERED

    (

    [Period] ASC,

    [Material_CD] ASC,

    [Plant_CD] ASC,

    [Batch_Num] ASC,

    [Customer] ASC,

    [Loaded_From] ASC

    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

    ) ON [PRIMARY]

    GO

  • After taking a quick look, I can tell you that you are right.

    The UPDATE FROM used in the trigger will affect all rows that match an inserted/updated row on the combination of three columns provided. Which works out to exactly the updated rows if that combination is exactly unique in the table - but since the primary key is on a combination of those three plus three additional columns, that is not guaranteed.

    So either the primary key is incorrectly defined, or the trigger is wrong.


    Hugo Kornelis, SQL Server/Data Platform MVP (2006-2016)
    Visit my SQL Server blog: https://sqlserverfast.com/blog/
    SQL Server Execution Plan Reference: https://sqlserverfast.com/epr/

  • Change this part of the UPDATE query in the trigger

    FROM ztb_Details A

    INNER JOIN inserted B

    on a.[plant-material] = b.[plant-material]

    and a.[batch_num] = b.[batch_num]

    and a.[Period] = b.[Period]

    to use all the columns from the primary key and you'll be sure that only the inserted columns are updated.

    [plant-material] is not part of the PK.

    i.e.

    FROM ztb_Details A

    INNER JOIN inserted B

    on

    a.[Period]=b.[Period]

    a.[Material_CD]=b.[Material_CD]

    a.[Plant_CD]=b.[Plant_CD]

    a.[Batch_Num]=b.[Batch_Num]

    a.[Customer]=b.[Customer]

    a.[Loaded_From]=b.[Loaded_From]

    Igor Micev,
    My blog: www.igormicev.com

  • ...and what if the intention was to update all rows matched on those three columns?

    Before you go changing something just because it "looks wrong", I suggest you check with the business whether they are having the data corruption you think it is causing and whether anyone knows what the trigger was designed to do.

    MM



    select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);

  • Forum Etiquette: How to post Reporting Services problems
  • [/url]
  • Forum Etiquette: How to post data/code on a forum to get the best help - by Jeff Moden
  • [/url]
  • How to Post Performance Problems - by Gail Shaw
  • [/url]

  • Hugo Kornelis (1/23/2016)


    After taking a quick look, I can tell you that you are right.

    The UPDATE FROM used in the trigger will affect all rows that match an inserted/updated row on the combination of three columns provided. Which works out to exactly the updated rows if that combination is exactly unique in the table - but since the primary key is on a combination of those three plus three additional columns, that is not guaranteed.

    So either the primary key is incorrectly defined, or the trigger is wrong.

    Yep... the PK is correct, the trigger is wrong.. There is only a few rows that overlap, between the three source files being loaded into this table... but if a user was to update one of those rows..then we would have bad data. (Either that has not happened yet, this table is just over a year old, or no one has noticed it yet.)

  • Viewing 5 posts - 1 through 4 (of 4 total)

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