Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 318375
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 12, 20262026-05-12T08:33:49+00:00 2026-05-12T08:33:49+00:00

Suppose I have these two tables: Invoice ——- iInvoiceID int PK not null dtCompleted

  • 0

Suppose I have these two tables:

Invoice
-------
iInvoiceID int PK not null
dtCompleted datetime null

InvoiceItem
-----------
iInvoiceItemID int PK not null
iInvoiceID int FK (Invoice.iInvoiceID) not null
dtCompleted datetime null

Each InvoiceItem might be fulfilled by a different process (executable) that runs on a different machine. When the process is complete, I want it to call a stored procedure to stamp the InvoiceItem.dtCompleted field, and I want this stored procedure to return back a flag indicating whether the entire invoice has been completed. Whichever process happens to be the one that finished the invoice is going to kick off another process to do some final business logic on the invoice, e.g. stamp the dtCompleted and send a receipt email. Obviously I want this other process to fire only once for a given Invoice.

Here is my naive implementation:

CREATE PROCEDURE dbo.spuCompleteInvoiceItem
    @iInvoiceItemID INT 
AS
BEGIN
    BEGIN TRAN

        UPDATE InvoiceItem 
        SET dtCompleted = GETDATE()
        WHERE iInvoiceItemID = @iInvoiceItemID

        IF EXISTS(SELECT * FROM InvoiceItem WHERE dtCompleted IS NULL 
                  AND iInvoiceID = (SELECT iInvoiceID FROM InvoiceItem
                                   WHERE iInvoiceItemID=@iInvoiceItemID))
            SELECT 'NotComplete' AS OverallInvoice
        ELSE
            SELECT 'Complete' AS OverallInvoice
    COMMIT
END

Is this sufficient? Or do I need to increase the transaction serialization level and if so, what level would provide the best balance of performance and safety?

Pre-emptive comments:

  • I know I could achieve the same business goal by implementing a central concurrency service at the process/executable level, but I think that’s overkill. My instinct is that if I craft my stored procedure and transaction well, I can use SQL Server as my inter-process concurrency service for this simple operation without heavily impacting performance or increasing deadlock frequency (have my cake and eat it too.)
  • I’m not worrying about error handling in this example. I’ll add the proper TRY/CATCH/ROLLBACK/RAISERROR stuff after.

Update 1:

According to the experts, not only do I need the most restrictive transaction isolation level — serializable — but I also need to lock all the InvoiceItems of a particular invoice before I do anything else, to ensure that other concurrent calls to the stored procedure will block until the current one completes. Otherwise I might get deadlocks. Here’s my latest version of the implementation:

CREATE PROCEDURE dbo.spuCompleteInvoiceItem
        @iInvoiceItemID INT 
    AS
    BEGIN
        IF @iInvoiceItemID IS NULL RAISERROR('@iInvoiceItemID cannot be null.', 16, 1)

        BEGIN TRAN

            SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

            DECLARE @iInvoiceID INT

            SELECT @iInvoiceID = iInvoiceID
            FROM InvoiceItem
            WHERE dtCompleted IS NULL 
            AND iInvoiceID = (SELECT iInvoiceID FROM InvoiceItem WHERE iInvoiceItemID=@iInvoiceItemID)

            IF @iInvoiceID IS NULL
            BEGIN
                -- Should never happen
                SELECT 'AlreadyComplete' AS Result
            END
            ELSE
            BEGIN
                UPDATE InvoiceItem SET dtCompleted = GETDATE() WHERE iInvoiceItemID = @iInvoiceItemID

                IF EXISTS(SELECT * FROM InvoiceItem WHERE iInvoiceID=@iInvoiceID AND dtCompleted IS NULL)
                    SELECT 'NotComplete' AS Result
                ELSE
                    SELECT 'Complete' AS Result
            END

        COMMIT

Thanks,

Jordan Rieger

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-12T08:33:49+00:00Added an answer on May 12, 2026 at 8:33 am

    Your problem here is if two processes simultaniously complete the remaining two items they are both going to think they finished the invoice.

    What you want is a lock on all the other detail items in the invoice to ensure nothing else can change the status whilst process is updating the status. This will of course reduce concurency but this should be limited to only the current invoice and should be fairly short.

    You can do this using the SERIALIZABLE isolation level to ensure that you cannot get phantom reads,

    
      DECLARE @iInvoiceId int
    
      BEGIN TRAN
    
      SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    
      SET NOCOUNT ON
    
      -- This select locks the rows and ensures that repeated
      -- selects will produce the same result
      -- ie no other transaction can affect these rows,
      -- or insert a row into this invoice
      SELECT @iInvoiceId = iInvoiceId FROM InvoiceItem WITH (xlock)
      WHERE iInvoiceId = (
        SELECT iInvoiceId FROM InvoiceItem WHERE iInvoiceItemId = @iInvoiceItemId)
    
      SET NOCOUNT OFF
      -- perform request of query as before
    
      COMMIT
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Suppose I have these two tables : TABLEA TABLEB ----------- ----------- ID | NAME
Suppose you have these tables: Table Name: Salesman Fields: S_ID(Primary Key), Name Table Name:
Let us suppose i have these three methods defined: int F1(int, int); int F1(float,
Suppose I have an IEnumerable<int> and I want these to be converted into their
Suppose I have two tables, t1 and t2 which are identical in layout but
for example suppose we have the two relations R1(A,B) R2(C,D) also these are the
Suppose I have two tables: Group ( id integer primary key, someData1 text, someData2
Suppose you have two tables in PostgreSQL. Table A has field x , which
Suppose I have two tables, Customer and Vendor. I want to have a common
Suppose I have two tables 1st table emp EmpID | EmpName|xyz...coloums 1. | Hrishi

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.