DML statement behaves unexpectedly (UPDATE Statement)

  • Hello -

    Was working with a rather simple update statement, and ran across a behavior that I am not 100% certain as to the origins of. I ran the following on 2 different server instances. One is SQL 2012 Enterprise Edition (x64) - (SQL Server 11.0.5058), and the other is SQL 2008 R2 Standard Edition (x64) - (SQL Server 10.50.2550). The version of SSMS being used is SQL 2012 (SSMS 11.0.2100.60), and here is the statement...

    while @@ROWCOUNT > 0

    BEGIN

    UPDATE Database2.dbo.HTT_INVENTORY_SIM

    SET ICCID_BATCH_ID = 'VST22620'

    WHERE ICCID_BATCH_ID = 'VST22626'

    AND ICCID_NUMBER in

    (

    select top 5000 ICCID_NUMBER from Database1.dbo.test_HTT_INVENTORY_SIM b

    where ICCID_NUMBER in

    (select ICCID_NUMBER FROM Database2.dbo.HTT_INVENTORY_SIM (nolock) WHERE ICCID_BATCH_ID = 'VST22626')

    )

    END

    When I run the above code against my 2012 server, it ran as I expected it to - in batches of 5,000 records (so as to avoid locking things up in once mass swoop). The total records being updated is only 25,000 but the system cannot be locked for any great length of time (when this was needing to be performed), hence the reason for batching it this way.

    However - when it runs against the 2008 R2 system (which is the PROD system in this scenario), it says command completed successfully, but no records were updated. I walked through each of the sub queries, but could find no problems or issues. I then ran it manually 5 times, and it worked fine.

    Anyone seen this behavior before? Is it possibly just a setting in SSMS that I am not aware of that behaves differently in my copy between the to instance versions?

    If you have the ability to set up a test with the logic above, and could share your results and insights - sure would appreciate it.

    Thank you

  • There is nothing before the @@ROWCOUNT check in the WHILE loop, so clearly one connection does SOMETHING on the spid that gets you an @@ROWCOUNT return other than 0.

    If you are going to do it this way, I would explicitly FORCE the start of the WHERE to work with this:

    SELECT top 1 * from sys.objects

    WHILE @@ROWCOUNT > 0

    BEGIN

    ...

    END

    Oh, I also note that you do not have any explicit BEGIN TRAN/CHECK FOR ERROR/COMMIT OR ROLLBACK in your loop. That is a must!!

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • thank you so much! I will test this out, and yes - I normally treat all my DML as Transactions, but here in my new position - they do a full copy of the table to a test table (so as to avoid any mistakes). I will incorporate both just for safer keeping.

    Thanks again!

  • Oh, another thing I do when batching bulk stuff like this is to drop in a WAITFOR DELAY '00:00:0.x' or something appropriate to give the server some breathing room and let other processes have a crack at potentially locked resources. The explicit tran stuff becomes important for this to work.

    I also often check the tlog size and kick off backups as required to keep from filling it up if I have any sizable activity to handle.

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • Tried posting how I might approach writing this update, but couldn't do it directly from work. When I got home last night, didn't even get on my computer so didn't post it then either.

    Attached is a file with the code I wrote yesterday. It is not syntax checked, nor is it tested (no database/schema/data) so no promises out of the box. If some one would like to post the code in an IFcode block for all to see, thanks.

    Please note that the CATCH block is not fleshed out.

    Edit: Added rollback to the CATCH block. I don't know how I missed that when I first wrote this code snippet.

  • Lynn Pettis (1/28/2016)


    Tried posting how I might approach writing this update, but couldn't do it directly from work. When I got home last night, didn't even get on my computer so didn't post it then either.

    Attached is a file with the code I wrote yesterday. It is not syntax checked, nor is it tested (no database/schema/data) so no promises out of the box. If some one would like to post the code in an IFcode block for all to see, thanks.

    Please note that the CATCH block is not fleshed out.

    Here is the code (unchanged from attachment).

    declare @Batch int = 5000;

    while @Batch > 0

    begin

    begin tran;

    begin try;

    update top (@Batch) his2 set

    ICCID_BATCH_ID = 'VST22620'

    from

    Database2.dbo.HTT_INVENTORY_SIM his2

    inner join Database1.dbo.test_HTT_INVENTORY_SIM his1

    on his2.ICCID_NUMBER = his1.ICCID_NUMBER

    where

    his2.ICCID_BATCH_ID = 'VST22626';

    set @Batch = @@rowcount;

    commit;

    waitfor delay '00:00:00.050';

    end try

    begin catch;

    print 'Error occurred';

    -- error code goes here

    end catch;

    end

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Thanks, Phil.

  • Hey Phil, can you add a rollback in the CATCH block? I just noticed that I forgot that in the code I uploaded.

    I fixed the code I had uploaded in the earlier post.

  • Lynn Pettis (1/28/2016)


    Hey Phil, can you add a rollback in the CATCH block? I just noticed that I forgot that in the code I uploaded.

    I fixed the code I had uploaded in the earlier post.

    Sure. Here's a modified version:

    declare @Batch int = 5000;

    while @Batch > 0

    begin

    begin tran;

    begin try;

    update

    top (@Batch) his2

    set ICCID_BATCH_ID = 'VST22620'

    from Database2.dbo.HTT_INVENTORY_SIM his2

    inner join Database1.dbo.test_HTT_INVENTORY_SIM his1 on his2.ICCID_NUMBER = his1.ICCID_NUMBER

    where his2.ICCID_BATCH_ID = 'VST22626';

    set @Batch = @@rowcount;

    commit;

    waitfor delay '00:00:00.050';

    end try

    begin catch;

    print 'Error occurred';

    if @@TRANCOUNT > 0

    rollback transaction;

    end catch;

    end

    Alternatively, a SET XACT_ABORT ON at the start would do the same job.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • I like your modification better than mine. I left out the check of @@TRANCOUNT in the code I reposted in my attachment. Definitely a good idea to have but I'm not going to make that change. Hopefully people finding this thread will read the whole thread.

Viewing 10 posts - 1 through 9 (of 9 total)

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