views:

61

answers:

1

I want to guarantee that a token is assigned to an order. All available tokens are inside the Token table and each token can ONLY be assigned to 1 order. Here is the sql I came up with:

SET XACT_ABORT ON;
BEGIN TRANSACTION

-- Reserve token.
SELECT @token = token, @tokenId = id FROM Tokens WITH (UPDLOCK) WHERE taken = 0;
-- Take token.
UPDATE Tokens SET taken = 1 WHERE id = @tokenId;
-- Assign token to the order.
UPDATE Orders SET token = @token WHERE ID = @orderId;

COMMIT TRANSACTION

Can the above code guarantee that

  1. if there is an available token inside Tokens table, then it will be selected and assigned to an order.
  2. each token will not be assigned to more than 1 order.
  3. Statement will never fail in error.

Do you see any other potential problems with this statement?

+2  A: 

Instead of aenter code here "taken" attribute, why not just put a nullable OrderId in the token table. This accomplishes yr objectives with just one column attribute.

Update Tokens SET 
  Orderid = @orderId  
Where tokenId = (Select Min(TokenId)
                 From Tokens
                 Where Orderid is Null)

EDIT: Added schema to illustrate one to zero or one relationship

Tokens
TokenId integer non-null PK
... other attributes
enter code here


Orders
OrderId Integer Non-Null PK, FK to Tokens.TokenId
... other attributes

Now, all you need to do is use an available tokenId from the tokens table when you create the new Orders record.

Insert Orders (OrderId, [Other attributes])
Select Min(TokenId), [Other values]
From Tokens t
Where Not Exists
  (Select * From Orders
   Where OrderId = t.TokenId)
Charles Bretana
+1. You would need a check constraint to make sure the token wasn't used on more than one order, since SQL Server sadly doesn't allow for nullable unique constraints (well it does, but in a screwy way).
Phil Sandler
@Phil, No you wouldn't... You are not putting tokens on orders at all, you are putting the orderId on a Token... The OrderId column is on the Tokens table, there is only one such column, and it can only hold a single value. And why would you need a unique constraint ? The op doesn't say that the same Order can't be assigned to more than one token, only that the token can't be asigned to more than one order.
Charles Bretana
You're right--it doesn't explicitly say that. However his original structure (with token on the Orders table) implies that each order can only have 0-1 tokens.
Phil Sandler
@Charles, thanks for your suggestion, but it's part of the requirement to have token inside the orders table.@Phil, you're right each order must have 0-1 token.
niaher
@Phil, you're right, buy I (incorrrectly) assumed that the structure (schema) was in fact the aspect under discussion, and therefore that what it implied was not germane. @niaher, what you are saying is that the relationship is one to zero or one, (what is called a subclass relationship). In that case you shoulod consider using the same integer value for both tokenId and OrderId. I'll add another schema to answer to illustrate.
Charles Bretana