Updating in a cursor

  • Hi there

    I'm having a wee bit of a problem. I've declared a cursor and have selected multiple rows from a DB to get some data, then do some manipulation on that data to send a email. Once thats done, I'm trying to update the table again and set the row as processed.

    The table I'm selecting data from and then trying to update is on another server and I think this whole little process is going a little over my head.

    Here's a brief idea of whats happening:

    CREATE PROCEDURE CallLogSendEmail

    AS

    DECLARE @emailRcpts varchar(50)

    DECLARE @emailMsg varchar(255)

    DECLARE @data varchar(255)

    DECLARE@logID int

    DECLARE @notification int

    DECLARE @emailSentResult int

    SET @emailRcpts = 'bob@accounting.com'

    DECLARE xLogCursor CURSOR FOR

    SELECT ID, Data, Notification

    from [SERVER1].DB.dbo.CallLog

    WHERE Notification = 0

    OPEN xLogCursor

    FETCH NEXT FROM xLogCursor

    INTO @logID, @data, @notification

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SELECT @emailMsg = 'Some extra text and string manipulatio on the data' + @data

    exec @emailSentResult=SERVER2.master..xp_sendmail @message=@emailMsg, @subject='test', @recipients = @emailRcpts

    IF @emailSentResult = 1

    BEGIN

    UPDATE [SERVER1].DB.dbo.CallLog

    SET Notification = 1

    WHERE CURRENT OF xLogCursor

    END

    FETCH NEXT FROM xLogCursor

    INTO @logID, @data, @notification

    END

    COMMIT

    CLOSE xLogCursor

    DEALLOCATE xLogCursor

    GO

    The error I get is this:

    Remote tables are not updatable. Updatable keyset-driven cursors on remote tables require a transaction with the REPEATABLE_READ or SERIALIZABLE isolation level spanning the cursor.

    Now, I've tried creating a transaction with the SET CURSOR_CLOSE_ON_COMMIT OFF command set, then encapsulate the update with a BEGIN TRAN and COMMIT, but it doesn't seem to do anything, if I do the TRAN outside the cursor, everything seems to go horribly wrong. I've also read up the help files on REPEATABLE_READ and SERIALIZABLE and it seems to mostly be going over my head.

    Any help or shove in the right direction would be greatly appreciated.

    Thanks

    Syn

  • Never mind.

    Did a FOR READ ONLY on the select statement and then did a normal update on the table with the ID.

    If there is a beter way of doing this, I'd still like to know.

    Thanks

    Syn

  • Have you tried setting the transaction isolation level?

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    Do this inside the body of the stored proc, before you declare the cursor.

  • SQLZ (10/28/2008)


    Have you tried setting the transaction isolation level?

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    Do this inside the body of the stored proc, before you declare the cursor.

    I did read that section in the help file, but it simple didn't make much sense to me 🙁

  • Garth Michel (10/28/2008)


    SQLZ (10/28/2008)


    Have you tried setting the transaction isolation level?

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

    Do this inside the body of the stored proc, before you declare the cursor.

    I did read that section in the help file, but it simple didn't make much sense to me 🙁

    Transaction isolation refers to the mechanism that SQL Server uses to isolate different transactions from each other. For example, if I'm updating data in a table then SQL Server can isolate other transactions from viewing or updating that data.

    There are four isolation levels (we'll ignore snapshot isolation), each with a varying degree of isolation.

    read uncomitted offers virtually no isolation. So if you're updating a table, I can happily come along and read that data even though you might have not finished updating the data in that table.

    In read committed (the default isolation level) if I'm reading data from a table, that data is locked until I've finished reading that data (i.e. until my select statement completes). Also, if you're updating data no one else can read the data until you're done with updating it.

    In repeatable read if I'm reading data from the table, the data is locked until the end of the transaction. Other transaction can still insert data.

    Serializable offers the most isolation, where data is completely locked until the end of the transaction.

    Hope that helps.

  • Isn't me setting the SELECT to READ ONLY pretty much the same as setting the mode to repeatable read and would this mode be sufficient for what I want to do?

    Syn

  • Garth Michel (10/28/2008)


    Isn't me setting the SELECT to READ ONLY pretty much the same as setting the mode to repeatable read and would this mode be sufficient for what I want to do?

    Syn

    Unfortunately it's not the same. Imagine this:

    You run the select against CallLog for the cursor and 5 seconds later you perform the update statement on CallLog. How do you know that in those 5 seconds the data in the table CallLog has not changed because another transaction modified the data?

    The answer is that you can't know for sure.

    By running in repeatable read or in serializable you are ensuring that the table CallLog cannot be modified by another transaction until your transaction is finished.

Viewing 7 posts - 1 through 6 (of 6 total)

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