SET IDENTITY_INSERT 从 SQL Server 2000 到 2005 的行为有何不同?

Posted

技术标签:

【中文标题】SET IDENTITY_INSERT 从 SQL Server 2000 到 2005 的行为有何不同?【英文标题】:Difference in behavior for SET IDENTITY_INSERT from SQL Server 2000 to 2005? 【发布时间】:2009-09-08 21:11:13 【问题描述】:

我有一个应用程序(当前)需要使用 SQL Server 2000 和 SQL Server 2005 提供的数据库。

我正在尝试以编程方式将数据库从一台服务器移动到另一台服务器。我使用的所有表都有一个自动递增的主键。由于这些自动增量键在其他表中用作外键,因此我复制表的攻击计划是暂时关闭目标表上的自动增量,逐字插入记录(使用原始主键),然后打开自动-重新增加。

如果我理解正确,我可以通过执行一次“打开/关闭自动增量”一个表

SET IDENTITY_INSERT tbl_Test ON;
...
SET IDENTITY_INSERT tbl_Test OFF;

我的实现是在 VB 2005 中,使用 System.Data.SqlClient。

为简洁起见,我将只展示与构建 SQL 查询相关的代码行。

创建表:

    Dim createTableStatement As String = _
        "CREATE TABLE tbl_Test (" & _
            "ID_Test INTEGER PRIMARY KEY IDENTITY," & _
            "TestData INTEGER" & _
            ")"
    Dim createTableCommand As New SqlCommand(createTableStatement, connection)

    createTableCommand.ExecuteNonQuery()

打开或关闭 IDENTITY_INSERT:

    Dim turnOffIdentInsertStatement As String = _
        "SET IDENTITY_INSERT tbl_Test OFF;"
    Dim turnOffIdentInsertCommand As New SqlCommand(turnOffIdentInsert, connection)
    turnOffIdentInsertCommand.ExecuteNonQuery()

    Dim turnOnIdentInsertStatement As String = _
        "SET IDENTITY_INSERT tbl_Test ON;"
    Dim turnOnIdentInsertCommand As New SqlCommand(turnOnIdentInsert, connection)
    turnOnIdentInsertCommand.ExecuteNonQuery()

正常插入新记录,不指定主键:

    Dim insertRegularStatement As String = _
        "INSERT INTO tbl_Test (TestData) VALUES (42);"
    Dim insertRegularCommand As New SqlCommand(insertRegularStatement, connection)
    insertRegularCommand.ExecuteNonQuery()

使用显式主键插入新记录:

    Dim insertWithIDStatement As String = _
        "INSERT INTO tbl_Test (ID_Test, TestData) VALUES (20, 42);"
    Dim insertWithIDCommand As New SqlCommand(insertWithIDStatement, connection)
    insertWithIDCommand.ExecuteNonQuery()

所以,我的计划是调用打开 IDENTITY_INSERT 的代码,使用显式主键添加记录,然后关闭 IDENTITY_INSERT。

当我与 SQL Server 2000 交谈时,此方法似乎工作正常,但当我尝试对 SQL Server 2005 完全相同的代码时遇到异常:

"Cannot insert explicit value for identity column in table 'tbl_Test' when IDENTITY_INSERT is set to OFF."

有什么提示吗?一如既往地提前感谢。

【问题讨论】:

【参考方案1】:

SqlBulkCopy 值得一看,因为它在导入批量数据方面进行了优化。

根据具体情况,还值得研究的是使用 SSIS 任务批量复制数据(也使用批量复制 API)或使用 BULK INSERT 语句链接服务器(同样,批量复制 API)。

至于设置身份,set identity_insert 语句是在与插入相同的连接上执行的吗?由于 SQL Server 2005 仅在当前连接上保留该设置。

因为以下对我来说在 SQL Server 2008 Express 上运行良好:

using (var conn = CreateConnection())

    conn.Open();
    new SqlCommand("SET IDENTITY_INSERT Foo ON", conn).ExecuteNonQuery();
    new SqlCommand("INSERT INTO Foo(id) VALUES (1)", conn).ExecuteNonQuery();
    new SqlCommand("SET IDENTITY_INSERT Foo OFF", conn).ExecuteNonQuery();

【讨论】:

你找到了。我正在打开/关闭命令之间的连接。也感谢您将我指向 SqlBulkCopy! 啊……这会不会是偶然与隐式交易有关? 大卫,可能。不过,我还不够熟悉,无法确定。 SET IDENTITY_INSERT 不关心事务,它不参与其中。然而,它确实关心连接,它只为当前连接设置。我还没有测试范围,所以我不确定。【参考方案2】:

您可能需要在 SET IDENTITY ... ON 语句之后插入 GO 语句。

【讨论】:

感谢您抽出宝贵时间回复大卫!【参考方案3】:

在 SQL 查询分析器会话中,我会在 IDENTITY_INSERT 之后和实际插入之前发出 GO。也许这也适用于在代码中调用它?

【讨论】:

感谢您抽出宝贵时间回复!非常感谢。

以上是关于SET IDENTITY_INSERT 从 SQL Server 2000 到 2005 的行为有何不同?的主要内容,如果未能解决你的问题,请参考以下文章

SET IDENTITY_INSERT (Transact-SQL) 允许将显式值插入到表的标识列中

SET IDENTITY_INSERT OFF 的数据库范围等效项

SQL Server 错误:“无法为标识列插入显式值”,即使我 SET IDENTITY_INSERT ON

SET IDENTITY_INSERT

SET IDENTITY_INSERT ON|OFF 的解惑

set IDENTITY_INSERT on 和 off 的设置