Problem with trigger

  • Agree that the SQL for an after trigger appears simplier but try with a schema change and the after trigger.

    Alter TABLE [dbo].[cnsmr_accnt]

    add constraint cnsmr_accnt_PK primary key ( cnsmr_id )

    Then run these this test case:

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed )

    SELECT '17', '45688','7' union all

    SELECT '17', '45689','6' union all

    SELECT '17', '45690','7' union all

    SELECT '17', '45691','7'

    Msg 2627, Level 14, State 1, Line 4

    Violation of PRIMARY KEY constraint 'cnsmr_accnt_PK'. Cannot insert duplicate key in object 'dbo.cnsmr_accnt'.

    The statement has been terminated.

    SQL = Scarcely Qualifies as a Language

  • Paul White (6/25/2009)


    ...the AFTER trigger version of my code is simpler as expected:

    ALTER TRIGGER trg_cnsmr_accnt_ai

    ON dbo.cnsmr_accnt

    AFTER INSERT

    AS

    BEGIN

    IF@@ROWCOUNT = 0 RETURN;

    SET NOCOUNT ON;

    SET ROWCOUNT 0;

    ;WITHOrdered AS

    (

    SELECTcnsmr_id,

    cnsmr_id + '-' + CONVERT(VARCHAR(10), 100 + ROW_NUMBER() OVER (ORDER BY cnsmr_id ASC)) AS new_value

    FROMdbo.cnsmr_accnt

    WHEREcase_feed = '7'

    )

    UPDATEOrdered

    SETcnsmr_id = Ordered.new_value

    FROMinserted I

    JOINOrdered

    ON(Ordered.cnsmr_id = I.cnsmr_id)

    WHEREI.case_feed = '7';

    END;

    Hi,

    The code works OK, but if it is the same cnsmr_id and same case_feed, it inserts without incrementing the sequence.

    e.g. cnsmr_id cnsmr_accnt case_feed

    14 2345 7

    14 2345 7

    output is

    cnsmr_id cnsmr_accnt case_feed

    14-101 2345 7

    14-101 2345 7

    Expected is

    cnsmr_id cnsmr_accnt case_feed

    14-101 2345 7

    14-102 2345 7

    Thanks for your help.

    \\K

    ______________________________________________________________________________________________________________________________________________________________________________________
    HTH !
    Kin
    MCTS : 2005, 2008
    Active SQL Server Community Contributor 🙂

  • Carl Federl (6/25/2009)


    Figured out the problem with the trigger not matching the expected results as this requirement was missing:

    When new rows for case_feed = '7' then:

    The next sequence should begin after the last appended sequence.

    When no row for case_feed = '7' , then first row should start with 101

    Previously,the trigger had hard-coded to begin at 100.

    ALTER TRIGGER [dbo].[trig_test_insert]

    ON [dbo].[cnsmr_accnt]

    INSTEAD OF INSERT

    AS

    SET NOCOUNT ON

    IF 0 = (SELECT COUNT(*) FROM inserted ) RETURN

    -- case_feed not '7' union case_feed is '7'

    INSERT INTO dbo.cnsmr_accnt

    (cnsmr_id , cnsmr_accnt_id , case_feed )

    SELECT inserted.cnsmr_id + '-'

    + CAST( HighestAssignedSeq + ROW_NUMBER() OVER( ORDER BY inserted.cnsmr_id ) AS VARCHAR(6) )

    as cnsmr_id

    ,inserted.cnsmr_accnt_id

    ,inserted.case_feed

    FROMinserted

    CROSS JOIN

    /*

    When new rows for case_feed = '7' then:

    The next sequence should begin after the last appended sequence.

    When the first row, then start with 100

    */

    (SELECTCOALESCE( CAST ( MAX(SUBSTRING(cnsmr_id,CHARINDEX('-',cnsmr_id)+1,LEN(cnsmr_id))

    ) AS INTEGER ) , 100 ) As HighestAssignedSeq

    FROMdbo.cnsmr_accnt

    WHERECHARINDEX('-',cnsmr_id) > 0

    ANDcase_feed = '7'

    ) as case_feed_7_last

    WHERE inserted.case_feed = '7'

    UNION ALL

    SELECT inserted.cnsmr_id

    ,inserted.cnsmr_accnt_id

    , inserted.case_feed

    FROMinserted

    WHEREinserted.case_feed '7'

    go

    Test SQL

    begin tran

    delete from cnsmr_accnt

    -- Single row inserts

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed ) VALUES ('12', '45683','7')

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed ) VALUES ('13', '45684','7')

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed ) VALUES ('14', '45685','3')

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed ) VALUES ('15', '45686','7')

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed ) VALUES ('16', '45687','2')

    -- Multi row inserts

    INSERT INTO cnsmr_accnt (cnsmr_id , cnsmr_accnt_id , case_feed )

    SELECT '17', '45688','7' union all

    SELECT '18', '45689','6' union all

    SELECT '19', '45690','7' union all

    SELECT '20', '45691','7'

    select *

    fromcnsmr_accnt

    rollback

    Test case results are:

    cnsmr_idcnsmr_accnt_idcase_feed

    12-101456837

    13-102456847

    14 456853

    15-103456867

    16 456872

    17-104456887

    19-105456907

    20-106456917

    18 456896

    Hi Carl,

    I appreciate you efforts in resolving the problem.

    I tried your code.

    INSERT INTO dbo.cnsmr_accnt

    (cnsmr_id , cnsmr_accnt_id , case_feed )

    SELECT inserted.cnsmr_id + '-'

    + CAST( HighestAssignedSeq + ROW_NUMBER() OVER( ORDER BY inserted.cnsmr_id ) AS VARCHAR(6) )

    as cnsmr_id

    ,inserted.cnsmr_accnt_id

    ,inserted.case_feed

    FROMinserted

    here if the column cnsmr_accnt_id is removed along with inserted.cnsmr_accnt_id in your whole code,

    it gives me an error message:

    Msg 515, Level 16, State 2, Procedure trig_test_insert1, Line 8

    Cannot insert the value NULL into column 'cnsmr_accnt_id', table 'test_oltp_rn.dbo.cnsmr_accnt'; column does not allow nulls. INSERT fails.

    The statement has been terminated.

    The reason, I an eliminating cnsmr_accnt_id is that the application that loads the data in the database, loads into multiple tables, and the table where I want the sequence to be appended, I am checking for just two columns -- cnsmr_id and case_feed. Also there are some computed columns that will automatically get updated based on other columns.

    I will try to modify your code to see how it works.

    Thanks for all you effort..... trying to resolve the problem :hehe:

    I learned a lot and will continue to learn ...

    Thanks,

    \\K

    ______________________________________________________________________________________________________________________________________________________________________________________
    HTH !
    Kin
    MCTS : 2005, 2008
    Active SQL Server Community Contributor 🙂

  • Carl Federl (6/25/2009)


    Agree that the SQL for an after trigger appears simplier but try with a schema change and the after trigger.

    Bizarre. So if we change the question the answer changes? 😀

    Heh. So given a proper primary key (i.e. a way of identifying a row uniquely) we have a proper table and an AFTER trigger can be written to work easily. My contention is that the AFTER trigger is better suited to this problem than INSTEAD OF.

    Paul

  • From Paul White:

    Bizarre. So if we change the question the answer changes?

    Heh. So given a proper primary key (i.e. a way of identifying a row uniquely) we have a proper table and an AFTER trigger can be written to work easily. My contention is that the AFTER trigger is better suited to this problem than INSTEAD OF.

    In general, given a problem and multiple alternative solutions, then choose the simplier.

    If the alternative solutions are equally simple, choose the one with the least cost - how do balance development cost and run-time resource costs is an interesting question, which is best left for a different discusssion.

    If the alternative solutions are equally simple and costly, choose the one with the fewest dependencies.

    As the After or Instead of trigger alternative solutions are both equal in simplicity and cost, but the instead of does not have a dependency on constraints not existing, I would choose the instead of solution.

    SQL = Scarcely Qualifies as a Language

  • SQL_Quest:

    if the column cnsmr_accnt_id is removed along with inserted.cnsmr_accnt_id in your whole code, it gives me an error message:

    Msg 515, Level 16, State 2, Procedure trig_test_insert1, Line 8

    Cannot insert the value NULL into column 'cnsmr_accnt_id', table 'test_oltp_rn.dbo.cnsmr_accnt'; column does not allow nulls. INSERT fails.

    Yes, that will be true if the column is defined with a NOT NULL constraint and does not have a default constraint. You must specify a value for the column.

    The reason, I an eliminating cnsmr_accnt_id is that the application that loads the data in the database, loads into multiple tables, and the table where I want the sequence to be appended, I am checking for just two columns -- cnsmr_id and case_feed.

    In an "INSTEAD OF" trigger, the initiating statement is intercepted and if the action is not performed by the trigger, then the database state will not be changed. a simplified example to show this effect is to have an instead of trigger with only a "RETURN" in the body and you will see that the SQL statement has no effect.

    SQL = Scarcely Qualifies as a Language

  • Carl Federl (6/25/2009)


    Agree that the SQL for an after trigger appears simplier but...

    I'll go with the simpler one then 😀

    Anyhow, it seems the thread has it's answer and we have also shown that ROW_NUMBER works correctly in triggers which was the other question that came up.

    Paul

Viewing 7 posts - 16 through 21 (of 21 total)

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