SQL Server: insert next available int

2019-04-08 13:24发布

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.

4条回答
在下西门庆
2楼-- · 2019-04-08 14:09

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...

查看更多
Animai°情兽
3楼-- · 2019-04-08 14:16
INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable
查看更多
一纸荒年 Trace。
4楼-- · 2019-04-08 14:24

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.

查看更多
走好不送
5楼-- · 2019-04-08 14:30

Try it without VALUES:

INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable
查看更多
登录 后发表回答