September 19, 2007 at 12:57 pm
hi
how do i get the nextid for a non-identity column other then taking the max value and adding 1 to it
any help is appreciated
September 20, 2007 at 2:17 am
If this is a serious question you need to reword it and give more detail.
There is not enough information here, as it stands you have not stated any context to allow any answer to be given.
Please give some example data.
Regards
Shaun McGuile
'Fix the problem, not the blame!'
Hiding under a desk from SSIS Implemenation Work :crazy:
September 20, 2007 at 2:26 am
Unless you mean to not use the MAX function
and use something like;
DECLARE @NEXTID
SELECT @NEXTID = (SELECT TOP 1 [id_Column] FROM <table> ORDER BY [id_Column] DESC) + 1
to get the value.
Sounds like a home work question.
If so you failed, otherwise you need to read a good T-SQL book and practice your craft.
Regards
Shaun McGuile
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 3:03 am
"Sounds like a home work question.
If so you failed, otherwise you need to read a good T-SQL book and practice your craft":
Shaun,
It is posts like yours that stop newbies from asking for help on these forums. If the question is too trivial for you to answer politely then I suggest you go and look for some harder problems to solve.
Please note your solution does not work in a multi-user environment.
September 21, 2007 at 3:29 am
andyb
There is a difference between asking for help and having someone do your work for you.
One thing that everyone should learn is how to phrase a question with sufficient detail so that a concise answer can be given.
To be a DBA requires a certain level of ability - even to start on the path - asking for help when under pressure of work because you haven't time to pull the manual off the shelf is fine.
But not to have exaughsted all other avenues first (e.g. reading the manual(s)) is not acceptable.
I am one of the most friendliest, tolerant people on this planet, but laziness irks me somewhat.
What does a multi-user environment have to do with it?
My question still stands about the origional post - is the question about not using the MAX function or something entirely different?
regards,
Shaun McGuile
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 4:20 am
Oh I'm just getting started here.
andyb: Whats your solution?
Your comments have been non constructive and have not answered the origional post.
My solution works, no matter if used in a multi-user environment or not.
It gets the record containing the highest value in the column adds one to it and puts it into a variable.
No more, no less.
There is no mention of field type in the question nor what is to be done with the value once obtained - adding one to the field type limit will cause an overflow exception. E.g. for a tinyint max value is 255 adding one would set the value to 256 if the variable was then used as the value for a new record an exception would happen.
Please think about your comments before posting
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 4:30 am
I think the OP wants the functionality of an identity column without an identity column. I strongly recommend to convert the table via 'insert into select...' preceeded by 'set identity_insert on table-name'.
An alternative is to use a table with one row and a single int column. Lock it when you read and update this value to get the next sequential value. But I dont' know how this will behave with a 1000 users hitting return simultaneously.
September 21, 2007 at 4:41 am
Michael M: your latter suggestion is a possibilty.
Wrapping it up in a single transaction i.e. get the value update it and then use it via an insert trigger would surely be the way to go, would this not avoid any concurrent usage issues?
My origional question still stands why mess about like this in the first place?
It would be nice if the Susane actually contributed something more to this thread, don't you think?
Regards,
Shaun McGuile
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 5:32 am
Shaun, your solution does not mimic an identity column in a multi-user environment,
i.e. it does not guarantee uniqueness - two users requesting the nextID value at the same time could get the same value. In order to mimic a true identity column you will need to make sure that until the next value is created no-one can get hold of the original value i.e by wrapping it in a transaction and holding a lock until the next id value is created.
For example,
/*create table mytable
(id int primary key not null
)*/
GO
set xact_abort on
DECLARE @newid int
BEGIN TRAN
/*SELECT @newid =COALESCE(MAX(id),0) FROM mytable WITH (UPDLOCK,HOLDLOCK) -- using MAX*/
SELECT TOP 1 @newid = id FROM mytable WITH (UPDLOCK,HOLDLOCK) ORDER BY id DESC -- Not Using MAX
INSERT INTO mytable (id) SELECT COALESCE(@newid,0)+1
COMMIT TRAN
--select * from mytable order by 1
/*drop table mytable*/
Please note however that performance could be a problem with this solution depending upon the number of concurrent users / size of the table. Using an identity column instead would scale better.
September 21, 2007 at 6:20 am
Just a thought;
Is it that each insert is implicitly wrapped in a transaction thus multiple requests will be qued and not simultaneous?
Thus does -
INSERT INTO mytable ([id]) SELECT ((SELECT TOP 1 [id] FROM mytable] ORDER BY [id] DESC)+1)
not meet the requirements of the OP?
Please explain to me why you used the COALESCE function?
--
Shaun
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 6:35 am
You will still need the locking hints in order to avoid duplicates, i.e
INSERT INTO mytable ([id]) SELECT coalesce(((SELECT TOP 1 [id] FROM mytable WITH (UPDLOCK,HOLDLOCK) ORDER BY [id] DESC)+1),1)
The coalesce is used for the initial value i.e. when there is no data in the table.
September 21, 2007 at 6:53 am
The problem with selecting either the MAX or the TOP 1 DESC, even in the presence of the read locks that Andy included in the code, is that you only need one "smart guy" that slips in a WITH (NOLOCK) or sets the transaction isolation level to "READ UNCOMMITTED" or forgets to establish the read locks and BOOM! You can certainly prevent dupes by making the ID column either the Primary Key or a Unique Key, but if someone makes one of the previously mentioned "mistakes", someone's app is going to go BOOM on the insert. And none of these methods will prevent someone from inserting the maximum value of an INT (or whatever the datatype of the column is) and messing up the whole works.
When it's not an autonumbering IDENTITY column, these types of columns are called "Sequences" and if you don't think they're a bit of a hit on performance, consider that even the almighty ORACLE recommends setting up a "cache" of sequence numbers to improve performance.
If you really can't use an IDENTITY column, then put something like Andy's or Michael's method in an Instead-Of trigger (hate 'em) and you're done (most closely mimics an IDENTITY column). Or, you can make a function using Andy's method and then tell everyone to use the function in all Inserts.
As a side bar, if you do use Michael's method (affectionately known as a "Sequence Table"), then make sure that you use the MS SQL Server proprietary form of UPDATE to ensure that both the write of the new number and the return in the variable occur at the same time without an explicit transaction in a single query to prevent the inevitable deadlocks that will occur using any other method. The general form of that proprietary UPDATE is...
UPDATE yourtable
SET @variable = columnname = formula
The real key is that unless you use an IDENTITY column, you can (and probably will) experience all the same problems that Oracle's sequence.NextVal experiences including slightly slower batch inserts and people forgetting to use the sequencer (unless the trigger method is used).
--Jeff Moden
Change is inevitable... Change for the better is not.
September 21, 2007 at 6:58 am
Jeff,
thanks for the clarity.
--
Shaun
Hiding under a desk from SSIS Implemenation Work :crazy:
September 21, 2007 at 8:24 pm
You bet... thanks for the feedback.
--Jeff Moden
Change is inevitable... Change for the better is not.
February 14, 2008 at 12:57 pm
Interesting conversation. I'm in a situation where this applies. Has a solution been decided upon?
I am a .Net developer and do not have the luxury of a dba. I inherited an application where the primary key is a 6 digit number, but is stored as a string.
I need to find the Max(id) + 1 and insert a new row with Max(id) + 1, thus redefining Max(id).
I am worried about 2 users hitting the stored procedure and the sequence getting mixe up.
Ideas?
Viewing 15 posts - 1 through 15 (of 16 total)
You must be logged in to reply to this topic. Login to reply