问题
I'm dealing with a table in SQL Server that has a serial_no
column, which is defined as a non null int. It doesn't appear to be an auto incrementing field, as if I leave that column out of my insert statement I get an error saying that the serial_no
field cannot be null.
So how do I insert the next available number?
I tried this:
INSERT INTO mytable (serial_no) VALUES ( (SELECT MAX(serial_no)+1 FROM mytable))
but I get an error saying that subqueries cannot be used in this context.
EDIT: This table is used in an off the shelf product so I cannot change the design and make the serial_no column an auto increment.
回答1:
You can improve write concurrency with locking hints
INSERT INTO mytable (serial_no, value)
SELECT MAX (serial_no)+1, @value
FROM mytable WITH (ROWLOCK, XLOCK, HOLDLOCK)
If performance is't important, try TABLOCKX in place of ROWLOCK, XLOCK
However, given this isn't safe either you need to retry
DECLARE @retry bit
SET @retry = 1
WHILE @Retry = 1
BEGIN
BEGIN TRY
INSERT INTO mytable (serial_no, value)
SELECT MAX (serial_no)+1, @value
FROM mytable WITH (ROWLOCK, XLOCK, HOLDLOCK)
SET @Retry = 0
END TRY
BEGIN CATCH
IF ERROR_NUMBER() <> 2627 --PK violation
RAISERROR ('blah', 16, 1)
END CATCH
END
Or change to an IDENTITY column and do it properly...
回答2:
The error can be fixed by dropping the VALUES
INSERT INTO mytable (serial_no, value)
SELECT MAX(serial_no)+1 ,
@value
FROM mytable)
But this is a bad idea. There's a race condition on MAX(serial_no)+1 (e.g. two Inserts get the same value for Max(Serial_no).
You're better off using an auto increment field. You could also create a table that stores the current next value and increment it instead of using max.
回答3:
INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable
回答4:
Try it without VALUES:
INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable
来源:https://stackoverflow.com/questions/4853361/sql-server-insert-next-available-int