3

When I use SQL Server with an int based identity column, I always use the auto increment. But I'm needing to insert into an existing table that doesn't have the property set, and I'm wondering what is the best practices way of doing this.

The naive approach would be to query the data, increment it, and then use that for an insert.

For example:

INSERT INTO myTable
(
  ID,
  Data
)
Values
(
  (SELECT MAX(ID) FROM myTable) + 1,
  "My actual data."
)

But I'm unsure if this is actually the best approach. Namely, since this is all one statement, is there a risk for a heavily utilized system to have another row inserted between selecting the MAX(ID) and the insert.

Edit: Sql Server version 2012.

Edit 2: To specify, I'm looking for a DML solution as I do not have DDL rights to modify the table.

  • What version are you using? – LowlyDBA Jan 21 '15 at 19:55
  • 2012, I'll add it to the question. – Lawtonfogle Jan 21 '15 at 20:02
  • Of course there is. Just a wild idea: put the id-generator in a trigger and lock the whole table when generating the ID (check the docs for the most appropriate lock type). Of course if you have many concurrent inserts that will slow everything down a bit, but locking is the only way to ensure that no concurrent INSERTs can happen. – watery Jan 21 '15 at 20:20
  • Is putting an identity field on the table out of the question? – Steve Mangiameli Jan 23 '15 at 14:09
  • @SteveMangiameli Near enough to out of the question. Management will be more likely to shelve the project than change the production database in this way (because of rolling changes to other systems using the same database). – Lawtonfogle Jan 23 '15 at 14:43
3

The best option is to use the SEQUENCE object, introduced in 2012. Since it is an independent object, you don't run the risk of querying it at the same time and retrieving the same value - it'll always provide the next in the chain.

Set the object with a specific start and increment value, then call it to get the next value desired. One of the biggest benefits here is that you can also specify a number of values to be cached for faster retrieval if you're working with rapid inserts.

CREATE SEQUENCE seq_obj
    START WITH 1050
    INCREMENT BY 1
    CACHE 1000
GO

Then to get the next ID value, use:

SELECT NEXT VALUE FOR seq_obj

Which will provide 1050, then 1051, and so on and so forth.

MSDN article for full information on other properties.

  • I'm familiar with sequences from using them for identities in Oracle. The problem is I'm trying to do this as a db_datawriter but not a db_ddladmin. – Lawtonfogle Jan 21 '15 at 20:35
  • If using IDENTITY and SEQUENCE are out as options, I think you're more in the area of a hokey solution than best practices. – LowlyDBA Jan 21 '15 at 20:38
  • 1
    I guess this is more of a 'best practice given a bad situation' deal. I'll still prefer the best hokey solution over any old hokey solution. – Lawtonfogle Jan 21 '15 at 20:41
  • This method can have concurrency issues? Thanks in advance for answer – MacGyver Mar 31 '16 at 16:02
0

Given the answers above. If this is a one-off bulk insert, I'd create a temporary table with an identity column. Insert the data to it. And then select the data and insert to your target table.

You could set the identity start value, or start at 1 and add a fixed value when you do the final insert.

I can't check atmo but a believe data writer privileges should allow you to create your own #tables

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.