我有两张表:table1
(列id
:种子1000,增量1)& table2
(列id
:种子2000,增量1)。首先,我在table1
&中插入一些记录。 table2
。第二,我在table2
中插入table1
(使用identity_insert_on
),得到类似的内容:
1000 first_record_table1
1001 second_record_table1
1002 third_record_table1
2000 first_record_table2
2001 second_record_table2
第三:如果我在table1中添加一条新记录,我希望得到1003作为新id,但我得到2002。 (1003没有打破唯一的id规则,并且是table1的正确增量值,所以我没有看到任何理由跳转到最后一条记录并增加1,因为数据库似乎这样做)。
问题:如何获得1003作为新ID?
答案 0 :(得分:4)
identity
上的documentation非常明确:
列上的标识属性不保证以下内容:
值的唯一性 - 必须使用PRIMARY KEY或UNIQUE约束或UNIQUE索引强制执行唯一性。
事务中的连续值 - 插入多行的事务不能保证获得行的连续值,因为表上可能会出现其他并发插入。如果值必须是连续的,那么事务应该使用表上的独占锁或使用SERIALIZABLE隔离级别。
服务器重新启动或其他故障后的连续值 - 出于性能原因,SQL Server可能会缓存标识值,并且在数据库故障或服务器重新启动期间,某些分配的值可能会丢失。这可能导致插入时身份值的缺口。如果间隙不可接受,则应用程序应使用带有NOCACHE选项的序列生成器,或使用自己的机制生成键值。
重用值 - 对于具有特定种子/增量的给定标识属性,引擎不会重用标识值。如果特定的insert语句失败或者回滚insert语句,则消耗的标识值将丢失,并且不会再次生成。生成后续标识值时,这可能会导致间隙。
在大多数情况下,identity primary key
列只会执行预期的操作。插入新行时,它会创建一个大于任何先前值的新值。可能存在差距,但这不是主键的问题。
如果你想要一个填补空白的列,那么你必须编写一个触发器来分配值。
或者,您可以在查询中使用row_number()
来获取顺序值。
答案 1 :(得分:1)
增量1只表示下一条记录的ID大于最大记录的ID,而不是将使用所有数字。如果你想让1003作为新的ID,你必须自己做一些编程,并处理一旦达到2000就已经采用新的情况。
但是你永远不应该依赖任何生成的ID没有间隙。想象一下,你有2个课程。第一个会话插入一些东西,但尚未提交或回滚。第二个会话插入一些东西并提交。第一场会议回滚。你想怎么处理这个案子?您需要为第一个会话分配一些ID,并为第二个会话分配不同的ID。现在第一个会话回滚,因此其ID未使用。你想从第二个会话的ID中减去一个吗?非常糟糕的主意。阻止第二个会话,直到第一个回滚或已提交?非常糟糕的主意。
所以请忘记连续的ID,它们永远不会工作。唯一ID是您通常需要的,SQL Server保证它们。