1

I have an identity column that is also the primary key, of INT datatype. Due to the issue discussed here (cache loss), the identity has gaps and I chose to reseed to the previous value. In concrete terms, I have a situation that looks like this:

Table1

ID_PK    Field1
---------------
28       'd'
29       'e'
30       'h'
1029     'f'
1030     'g'

I looked around and couldn't find a clear answer to what happens when I make an insertion and the seed reaches the existent value that would break the constraint. Suppose I were to insert values 'x' and 'y' in two separated queries to the table, I can think of the following possibilities:

  1. The identity will be reseeded before the first insertion and I will have both values inserted correctly.

  2. The first insertion will fail, then the column will be reseeded, and only then the second insertion would succeed.

  3. Neither will work and I will have to explicitly call DBCC CHECKIDENT to reseed before inserting values in the table

So, which is it? Or none of the above? Would this behavior be different if I inserted a multi-row result query into Table1? Thanks in advance

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
LFB
  • 676
  • 2
  • 8
  • 20
  • 4
    Seems like an easy situation to test for yourself? – MJH Jun 01 '18 at 13:19
  • 3
    And this is why you should always think very carefully before you reseed your table. There's almost never a need to do it, I've never understood why people get so concerned that there will be gaps in the numbers. – DavidG Jun 01 '18 at 13:21
  • Why bother reseeding anyway? An `IDENTITY` column isn't meant the be sequential, so why does it matter is you're missing a few 1,000 digits? – Thom A Jun 01 '18 at 13:21
  • 1
    You beat me to it @DavidG! – Thom A Jun 01 '18 at 13:22
  • Bad practice of my part, I know now there are better ways to deal with that (including not concerning at all). But nevertheless, I already resseeded and was wondering what will happen when seed reaches the value. Either way, I thought the question was valid. Regarding MJH comment I really would test it myself, if there weren't triggers related to the table – LFB Jun 01 '18 at 13:26
  • 1
    You don't have to test it on that table. Test it in a sandbox environment and see what happens. – Thom A Jun 01 '18 at 13:29
  • Fair enough. Thanks either way guys – LFB Jun 01 '18 at 13:33
  • 1
    While I'm not sure if there's anything that traps it *before* it happens, you would absolutely get a PK violation if the INSERT was attempted and the new IDENTITY value matched an existing PK value. – Terry Carmen Jun 01 '18 at 13:36
  • 1
    Worth noting that you can fix this problem right now by reseeding again to a value that is greater than the existing maximum. – DavidG Jun 01 '18 at 13:41
  • @DavidG agreed, I was just curious. – LFB Jun 01 '18 at 13:47

3 Answers3

4

For completeness anyway, here's a script you can use to test:

USE Sandbox;
GO

CREATE TABLE test(ID int IDENTITY(1,1) PRIMARY KEY CLUSTERED, string char(1));
GO

INSERT INTO test (string)
VALUES ('a'),('b'),('c'),('d');
GO

SELECT *
FROM test;
GO

DELETE FROM test
WHERE string IN ('b','c');
GO

SELECT *
FROM test;
GO
DBCC CHECKIDENT ('dbo.test', RESEED, 1);
GO  
INSERT INTO test (string)
VALUES ('e'),('f');
GO

SELECT *
FROM test;
GO

INSERT INTO test (string)
VALUES ('g');
GO

SELECT *
FROM test;
GO
DROP TABLE test;

Running this script will give you the answer you need. If you wonder why I have used 1 as the RESEED value, this is explained in the documentation:

The following example forces the current identity value in the AddressTypeID column in the AddressType table to a value of 10. Because the table has existing rows, the next row inserted will use 11 as the value, that is, the new current increment value defined for the column value plus 1.

In my script, this means that the next row to be inserted after the RESEED will have a value of 2 for its IDENTITY, not 1 (as rows already existing in the table (ID's 1 and 4)).

As several have said in the comments though, there's really no need to use RESEED on an IDENTITY column. If you need to maintain a sequence, you should (unsurprisingly) be using a SEQUENCE: CREATE SEQUENCE (Transact-SQL)

Thom A
  • 88,727
  • 11
  • 45
  • 75
  • Thanks for your time, man. I know it's a mute question. Getting good practice from these, though. – LFB Jun 01 '18 at 13:51
2

It depends:

Scenario 1

You get duplicates in the IDENTITY column, as no unique index or PK constraint.

create table I (
    id int identity(1,1) not null,
    i int null
)

Scenario 2

You get the following error as the inserted value conflicts with the Primary Key constraint:

Msg 2627, Level 14, State 1, Line 1 Violation of PRIMARY KEY constraint 'PK__I__3213E83FE0B0E009'. Cannot insert duplicate key in object 'dbo.I'. The duplicate key value is (11). The statement has been terminated.

create table I (
    id int identity(1,1) not null primary key,
    i int null
)

This proves that IDENTITY on it's own does not guarantee uniqueness, only a UNIQUE CONSTRAINT does that.

MJH
  • 1,710
  • 1
  • 9
  • 19
0

To close, turns out it's (2).

First insertion fails, reseed is automatic to the highest value, and only next insertion suceeds. Multi-value insertions behave the same if any of the values would break the primary key constraint.

LFB
  • 676
  • 2
  • 8
  • 20