Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Manual Identity

Author  Topic 

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-17 : 20:06:29
Take the following..
use tempdb

create table pages
(
pageID int identity,
ordinal int
)

insert pages ( ordinal ) values ( 1 )
insert pages ( ordinal ) values ( 2 )

declare @Ordinal int
select @Ordinal = max(Ordinal) + 1 from Pages

insert pages ( ordinal ) values ( @Ordinal )

select * from pages order by ordinal


The value of the ordinal is used to order the pages and the pages have to have a unique ordinal value else some code which is used to change the ordinal will not work.

So I'm using the 'max' function to work out what the next value will be for a new page's position and, as you can see if you run the code, it works.

However, what if a concurrent transaction, B, is running at the same time as transacion, A, and uses max just after A has but before A has done its insert? In this situation, A and B will use the same ordinal value for the insert.

So the question is, how can I lock the max ordinal value after its been read until the end of a transaction?

Cheers,

XF

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-02-17 : 20:29:11
One way to deal with that situation is to have a table whose job it is is just to generate the next ID value.
ie:

--existing table:
create table OrdinalFactory
(Ordinal int identity(1,1)
,active bit)

--in your insert SP:

declare @Ordinal int
insert OrdinalFactory (active) values(1)
Select @Ordinal = scope_identity()

insert pages ( ordinal ) values ( @Ordinal )


Be One with the Optimizer
TG
Go to Top of Page

ehorn
Master Smack Fu Yak Hacker

1632 Posts

Posted - 2005-02-17 : 20:31:43
OrdinalFactory... Nice!
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2005-02-17 : 20:33:59
Why not put the identity on the ordinal column instead?
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-17 : 20:58:32
Because the ordinal needs to be updatable. The pages need to be re-orderable.
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-17 : 21:03:57
When you use GROUP, do the rows used to create the group rows have a shared lock put on them? They are being read right? So what if I put an exclusive lock on them so that another transaction couldn't even read them? Then the max couldn't be run until the first tran's insert had been commited??
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-17 : 21:30:00
I suppose that's not that different from a table lock.
Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-02-17 : 21:41:49
X-Factor, are you saying that after process A has completed it's read but before the insert is performed, that Process B still can't read from the table because process A hasn't committed it's transaction?

I assume that your table's order has nothing to do with the sequence the records were added. So after the table has been "reordered" by updating the ordinal column, and new records are added with incrementing ordinal values, aren't those new records out of order (until the next re-ordering)?


Be One with the Optimizer
TG
Go to Top of Page

spirit1
Cybernetic Yak Master

11752 Posts

Posted - 2005-02-18 : 05:57:25
well those kind of things usually get solved preety nicely with an extra status column.
so until the transaction is finished put the status to say 2 and when it's finished put it to 3 (or whatever you like).


Go with the flow & have fun! Else fight the flow
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-18 : 11:13:27
quote:
So after the table has been "reordered" by updating the ordinal column, and new records are added with incrementing ordinal values, aren't those new records out of order (until the next re-ordering)?


Errr yeah! A new page would have a default position at the end.
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2005-02-19 : 20:24:29
You could do it this way:

declare @Ordinal int
select @Ordinal = max(Ordinal) from Pages

insert pages ( ordinal )
select
max(Ordinal)+1
from
Pages
having
max(Ordinal) = @Ordinal

Of course, you will have to check to make sure it didn't fail, and decide what to do if it does.


quote:

Originally posted by X-Factor

Take the following..
use tempdb

create table pages
(
pageID int identity,
ordinal int
)

insert pages ( ordinal ) values ( 1 )
insert pages ( ordinal ) values ( 2 )

declare @Ordinal int
select @Ordinal = max(Ordinal) + 1 from Pages

insert pages ( ordinal ) values ( @Ordinal )

select * from pages order by ordinal


The value of the ordinal is used to order the pages and the pages have to have a unique ordinal value else some code which is used to change the ordinal will not work.

So I'm using the 'max' function to work out what the next value will be for a new page's position and, as you can see if you run the code, it works.

However, what if a concurrent transaction, B, is running at the same time as transacion, A, and uses max just after A has but before A has done its insert? In this situation, A and B will use the same ordinal value for the insert.

So the question is, how can I lock the max ordinal value after its been read until the end of a transaction?

Cheers,

XF



Codo Ergo Sum
Go to Top of Page

TG
Master Smack Fu Yak Hacker

6065 Posts

Posted - 2005-02-19 : 20:54:58
Ok, how about this. Since the ordinal column is just used for ordering the display, do away with Unique constraints and contention issues all together. Just allow new records to be instered with a NULL ordinal value. When you select out of that table, order by isNull(Ordinal,100000000). Since the newly inserted records would just be ordered randomly anyway it shouldn't matter.

Be One with the Optimizer
TG
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-20 : 16:20:40
quote:
well those kind of things usually get solved preety nicely with an extra status column.
so until the transaction is finished put the status to say 2 and when it's finished put it to 3 (or whatever you like).


Can you explain a bit more about what you mean?

quote:
Ok, how about this. Since the ordinal column is just used for ordering the display, do away with Unique constraints and contention issues all together. Just allow new records to be instered with a NULL ordinal value. When you select out of that table, order by isNull(Ordinal,100000000). Since the newly inserted records would just be ordered randomly anyway it shouldn't matter.


When would the page be given a non-null ordinal value?

The user doesn't manualy enter an ordinal value at any point. What happens is that they're given a list of pages and each page has an up and down arrow next to it. Using these buttons, the user can move shift a page around. So if page x is moved above page y, page x's ordinal value is swapped with page y's ordinal value. So if page x has a null value, upon the swap, it needs to be given a proper value and I think that leads back to the original problem.
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-20 : 16:25:13
quote:
You could do it this way:

declare @Ordinal int
select @Ordinal = max(Ordinal) from Pages

insert pages ( ordinal )
select
max(Ordinal)+1
from
Pages
having
max(Ordinal) = @Ordinal



Or I could just put a real unique constraint on the ordinal column and handle a clash. I'd handle it by having it try the insert up to a 1000 times and then throw an exception if it still hadn't worked.

I have not put a unique constraint on yet because when you swap values, the first update would result in the page x's and page y's ordinal value being the same. But I figure I could get around this by temporarily negating the value being swapped for one of the pages.
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2005-02-21 : 14:17:53
I don't think that would work because a constraint violation is a fatal error that would terminate the stored procedure. You would never get to your error handler code.

quote:
Or I could just put a real unique constraint on the ordinal column and handle a clash. I'd handle it by having it try the insert up to a 1000 times and then throw an exception if it still hadn't worked.

I have not put a unique constraint on yet because when you swap values, the first update would result in the page x's and page y's ordinal value being the same. But I figure I could get around this by temporarily negating the value being swapped for one of the pages.



Codo Ergo Sum
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-21 : 14:46:22
Ok. Then I'd try calling the sp again from the app.
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2005-02-21 : 16:05:39
You can do that, but it is a lot of work for the from end to deal with.

You could use the code I supplied, and just check the value of @@rowcout after the insert to see if it was <> 1. If it isn't, just loopback and try again. Limit it to a reasonable number of retrys, say 10 or less. That would mean you would only need one call to the DB from the front end.


quote:
Originally posted by X-Factor

Ok. Then I'd try calling the sp again from the app.




Codo Ergo Sum
Go to Top of Page

X-Factor
Constraint Violating Yak Guru

392 Posts

Posted - 2005-02-21 : 16:31:01
Yes ok. Thanks for your help.
Go to Top of Page
   

- Advertisement -