SQL Server中的身份列

6

为什么SQL Server不允许在一个表中有多个IDENTITY列?是否有特定的原因?


被采纳的答案关于原因是错误的。即使它允许你创建两个身份列,这也是毫无意义的,就像这里一样。 - Martin Smith
8个回答

7

为什么需要它?SQL Server会为每个带有IDENTITY列的表跟踪单个值(当前标识值),因此每个表只能有一个标识列。


2

SQL Server将标识存储在内部表中,使用表的ID作为其键。因此,SQL Server不可能在一个表中有多个Identity列。


2
身份列是数据库表中的一列(也称为字段),其功能如下:
  1. 唯一标识表中的每一行
  2. 由数据库生成的值组成
这与Microsoft Access中的AutoNumber字段或Oracle中的序列非常相似。
身份列与主键的不同之处在于,它的值由服务器管理,并且(除非是极少数情况)不能修改。在许多情况下,身份列用作主键,但并非总是如此。
SQL Server使用身份列作为引用特定行的关键值。因此,只能创建单个身份列。另外,如果没有显式指定身份列,则Sql server在内部存储一个包含每行键值的单独列。正如所述,如果您想要多个具有唯一值的列,可以使用UNIQUE关键字。

“Identity列...独特地标识了表中的每一行”-- 真的吗?那为什么这是可能的呢?:CREATE TABLE Test1 (col1 INTEGER IDENTITY) ; SET IDENTITY_INSERT Test1 ON ; INSERT INTO Test1 (col1) VALUES (1) ; INSERT INTO Test1 (col1) VALUES (1) ; SET IDENTITY_INSERT Test1 OFF ; SELECT col1 FROM Test1 - onedaywhen
1
如果SQL Server允许IDENTITY列包含重复值,那么“SQL Server使用标识列作为键值来引用特定行”这一说法怎么可能成立呢? - onedaywhen
Onedaywhen,你的评论没有意义。SQL Server不允许标识列包含重复值。 - Lisa
1
@Lisa - 是的,它确实有这样做。这在第一条评论中已经得到证明。“如果没有明确声明标识列,则SQL Server内部存储一个单独的列,其中包含每行的键值”。这是完全错误的。我猜你在想非唯一聚集索引中添加的唯一性标识符。关于这个答案也有人提出了问题在这里 - Martin Smith

2

因为微软意识到超过80%的用户只需要每个表格一个自增列,而要创建第二个(或更多)的解决方法很简单,即创建一个种子为1、增量为1的IDENTITY,然后创建一个计算列,将自动生成的值乘以一个因子来改变增量,并加上偏移量来改变种子。


1
是的,序列允许像表中的列一样具有多个标识符,但这里存在一些问题。在典型的开发场景中,我看过开发人员手动插入有效值到列中(应该通过序列插入)。随后,当序列尝试向表中插入值时,由于唯一键冲突可能会失败。
此外,在多开发者/多供应商场景下,开发人员可能会将同一序列用于多个表(因为序列与表没有链接)。这可能导致一个表中存在缺失值。即,TableA 可能获得值 1,而 TableB 可能使用值 2,而 TableA 将获得 3。这意味着 TableA 将具有 1 和 3(缺少 2)。
除此之外,还有另一种情况,即您拥有每天截断的表。由于序列与表没有任何链接,截断的表将继续使用 Seq.NextVal(除非您手动重置序列),导致缺失值或甚至更危险的算术溢出错误。
由于上述原因,我认为 Oracle 序列和 SQL Server 标识列都适合各自的目的。我希望 Oracle 实现 Identity 列的概念,而 SQL Server 实现序列概念,以便开发人员可以根据自己的需求实现两者中的任何一种。

这个问题是关于标识列的,而不是序列对象(从SQL Server 2012开始可用)。 - Jon Seigel

0
一个identity列的整个目的是为了在表中每一行都包含一个唯一值。那么为什么在任何给定的表中需要多个identity列呢?
如果你真的有需要使用多个identity列,也许你需要澄清你的问题。

真的吗?那为什么这是可能的呢? CREATE TABLE Test1 (col1 INTEGER IDENTITY) ; SET IDENTITY_INSERT Test1 ON ; INSERT INTO Test1 (col1) VALUES (1) ; INSERT INTO Test1 (col1) VALUES (1) ; SET IDENTITY_INSERT Test1 OFF ; SELECT col1 FROM Test1 ; - onedaywhen

0

身份列用于唯一标识表中的单个行。如果您希望其他列也是唯一的,可以为每个可能需要的“身份”列创建一个唯一索引。


真的吗?那为什么这是可能的呢?:CREATE TABLE Test1 (col1 INTEGER IDENTITY) ; SET IDENTITY_INSERT Test1 ON ; INSERT INTO Test1 (col1) VALUES (1) ; INSERT INTO Test1 (col1) VALUES (1) ; SET IDENTITY_INSERT Test1 OFF ; SELECT col1 FROM Test1 - onedaywhen

-1

我一直认为这是 SQL Server 的一个任意且不好的限制。是的,你只想要一个标识列来实际标识一行,但有合理的理由让数据库自动生成多个字段的数字。

这就是 Oracle 中序列的好处。它们不与表绑定。您可以使用几个不同的序列来填充同一张表中尽可能多的字段。您也可以让多个表共享同一个序列,虽然这可能是一个非常糟糕的决定。但重点是您可以这样做。它更加精细并且给您更多的灵活性。

序列的不好之处在于您必须编写代码来实际递增它们,无论是在插入语句中还是在表上的 on-insert 触发器中。SQL Server identity 的好处在于,您只需更改属性或添加关键字到您的表创建中,就完成了。


这是两个完全不同的概念。一个是身份的概念,可能由生成的序列进行管理。另一个是生成的序列。对其中一个的抱怨并不意味着对另一个有不良情绪。 - Mark Canlas
99.9% 的情况下,SQL Server 的 IDENTITY 列和 Oracle 的序列用于同一目的:作为数据库生成的键,以为行提供唯一性。 但是,您可以以其他方式使用 Oracle 序列,这是使用 IDENTITY 列无法实现的。 我指出其他数据库供应商承认需要能够为表中的多个字段自动生成值,并且 SQL Server 不支持此功能。 问题的作者似乎感到困惑和恼火,我赞同这种情绪。 - Aaron Daniels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接