Cannot add identity column, using the SELECT INTO statement, to table 'dbo.NewUsers', which already has column 'UserID' that inherits the identity property.

SELECT INTO 语句创建一个新表并用 SELECT 语句的结果集填充它。SELECT INTO 可用于将多个表或视图中的数据组合到一个表中。它还可用于创建包含从链接服务器中选择的数据的新表。

新表的结构由选择列表中表达式的属性定义。当计算列包含在选择列表中时,新表中的对应列不是计算列。新列中的值是在执行 SELECT INTO 时计算的值。

如果源表中的列是 IDENTITY 列,则新表将在创建新表时继承该列的 IDENTITY 属性。为了说明,以下脚本将基于 [dbo].[Users] 表创建一个新表,并且新表将继承 [UserID] 列的 IDENTITY 属性:

CREATE TABLE [dbo].[Users] (
    [UserID]        INT IDENTITY(1, 1) NOT NULL,
    [UserName]      VARCHAR(50) NOT NULL,
    [FirstName]     VARCHAR(100) NOT NULL,
    [LastName]      VARCHAR(100) NOT NULL
)
GO

SELECT *
INTO [dbo].[Users2]
FROM [dbo].[Users]
GO

如果要将新列定义为 SELECT INTO 语句创建的新表的 IDENTITY 列,则可以使用 IDENTITY 函数。IDENTITY 函数仅在带有 INTO <table> 子句的 SELECT 语句中用于将标识列插入到新表中。虽然相似,但 IDENTITY 函数不是用于 CREATE TABLE 和 ALTER TABLE 语句的 IDENTITY 属性。

IDENTITY 函数的语法如下:

IDENTITY( <data_type> [, <seed>, <increment> ] ) AS <column_name>

<data_type> 参数是标识列的数据类型。标识列的有效数据类型是整数数据类型类别的任何数据类型,位数据类型或十进制数据类型除外。<seed> 参数是要分配给表中第一行的整数值。

不幸的是,使用带有 SELECT INTO 语句的 IDENTITY 函数来创建源表已经包含 IDENTITY 列的新表会产生错误,从以下语句可以看出:

SELECT IDENTITY(INT, 1, 1) AS [NewID], * 
INTO [dbo].[NewUsers]
FROM [dbo].[Users]
ORDER BY [UserName]

Msg 8108, Level 16, State 1, Line 1
Cannot add identity column, using the SELECT INTO statement, to table 'dbo.NewUsers',
which already has column 'UserID' that inherits the identity property.

解决方案/解决方法:

通过从源表中删除列的 IDENTITY 属性可以轻松克服此错误,以便由 IDENTITY 函数创建的新列可以具有新表的 IDENTITY 属性。在 SELECT INTO 语句中使用时,有几种方法可以删除列的 IDENTITY 属性。

第一种方法是使用 IDENTITY 列执行数学函数,从以下脚本可以看出:

SELECT IDENTITY(INT, 1, 1) AS [NewID], [UserID] * 1 AS [OldUserID],
       [UserName], [FirstName], [LastName]
INTO [dbo].[NewUsers]
FROM [dbo].[Users]

SELECT IDENTITY(INT, 1, 1) AS [NewID], [UserID] + 0 AS [OldUserID],
       [UserName], [FirstName], [LastName]
INTO [dbo].[NewUsers]
FROM [dbo].[Users]

有趣的是,如果使用 SELECT INTO 语句创建了一个新表,并且将两个表而不是一个表用作源表并且两个表都包含 IDENTITY 列,则不会生成此错误。新表不继承两个表中 IDENTITY 列的 IDENTITY 属性。为了说明,以下脚本使用 SELECT INTO 语句创建一个新表,其中连接了 2 个表,并且两个表都包含 IDENTITY 列:

CREATE TABLE [dbo].[Customer] (
    [CustomerID]            INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
    [FirstName]             VARCHAR(50),
    [LastName]              VARCHAR(50)
)

CREATE TABLE [dbo].[CustomerAddress] (
    [CustomerAddressID]     INT IDENTITY(1, 1) NOT NULL,
    [CustomerID]            INT NOT NULL REFERENCES [dbo].[Customer] ( [CustomerID] ),
    [Address1]              VARCHAR(100) NOT NULL,
    [Address2]              VARCHAR(100) NULL,
    [City]                  VARCHAR(50) NOT NULL,
    [State]                 CHAR(2) NOT NULL,
    [ZIP]                   VARCHAR(10) NOT NULL
)

SELECT A.[CustomerID], A.[FirstName], A.[LastName], B.[CustomerAddressID],
       B.[Address1], B.[Address2], B.[City], B.[State], B.[ZIP]
INTO [dbo].[AllCustomerAddresses]
FROM [dbo].[Customer] A INNER JOIN [dbo].[CustomerAddress] B
                                ON A.[CustomerID] = B.[CustomerID]

结果表将不会继承 [CustomerID] 和 [CustomerAddressID] 的 IDENTITY 属性,并且新表将没有任何 IDENTITY 列。鉴于此,可以使用 IDENTITY 函数为新表生成 IDENTITY 列。

SELECT IDENTITY(INT, 1, 1) AS [AllCompanyAddressesID], A.[CustomerID], A.[FirstName],
       A.[LastName], B.[CustomerAddressID], B.[Address1], B.[Address2], B.[City], B.[State],
       B.[ZIP]
INTO [dbo].[AllCompanyAddresses]
FROM [dbo].[Customer] A INNER JOIN [dbo].[CustomerAddress] B
                                ON A.[CustomerID] = B.[CustomerID]
GO

在这种情况下,避免此错误消息(消息 8108)的替代方法是在使用 SELECT INTO 语句时对源表执行 JOIN 以创建新表。如果只有一个表可用并且它不能与任何其他表连接,则它可以连接到自身并仍然生成所需的结果,如下所示:

SELECT IDENTITY(INT, 1, 1) AS [NewID], A.[UserID] AS [OldUserID], A.[UserName],
       A.[FirstName], A.[LastName]
INTO [dbo].[NewUsers]
FROM [dbo].[Users] A INNER JOIN [dbo].[Users] B
                             ON A.[UserID] = B.[UserID]

 

posted @ 2022-02-10 11:41  未风  阅读(73)  评论(0编辑  收藏  举报