2

我正在将一套 MS Access 后端数据库升级到 SQL Server。我编写了 SQL 脚本以在 SQL Server 中创建表模式。现在我正在尝试填充表格。大多数表都有自动编号的主键。这是我的一般方法:

For each TblName in LinkedTableNames
    'Create linked table "temp_From" that links to the existing mdb'
    'Create linked table "temp_To" that links to the new SQL server table
    ExecutePassThru "SET IDENTITY_INSERT " & TblName & " ON"
    db.Execute "INSERT INTO temp_To SELECT * FROM temp_From", dbFailOnError
    ExecutePassThru "SET IDENTITY_INSERT " & TblName & " OFF"
Next TblName

第一次插入立即发生。随后的插入尝试失败并出现错误:“当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'TblName' 中插入标识列的显式值。”

我为该特定错误添加了一个 Resume 语句,还添加了一个计时器。事实证明,错误持续了整整 600 秒(十分钟),然后插入成功进行。

MS Access 是否每 10 分钟自动刷新一次其 ODBC 会话?有没有办法让这种情况发生得更快? 我错过了一些明显的东西吗?

对于那些马上想说“使用升迁向导”的人的背景信息:
我没有使用内置的升迁向导,因为我需要能够从头到尾编写整个操作的脚本。目标是在客户端位置执行切换之前在测试环境中运行它。

4

3 回答 3

2

我找到了第一个问题的答案。十分钟是隐藏在 Jet 引擎项下的注册表中的设置:

'Jet WinXP/ Win7 32-bit:'
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\ODBC\ConnectionTimeout

'Jet Win7 64-bit:'
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\ODBC\ConnectionTimeout

'ACE WinXP/ Win7 32-bit:'
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Access Connectivity Engine\Engines\ODBC\ConnectionTimeout

'ACE Win7 64-bit:'
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\MicrosoftAccess Connectivity Engine\Engines\ODBC\ConnectionTimeout

此处记录了 ACE :

ConnectionTimeout:缓存连接在超时之前可以保持空闲的秒数。默认值为 600(值为 REG_DWORD 类型)。

该键被设置为默认值 600。即 600 秒或 10 分钟。我将它缩短到十秒,代码相应地加快了速度。

这绝不是完整的解决方案,因为将默认值设置为低肯定会在其他地方引起问题。事实上,Tony Toews 曾经建议在使用无 DSN 连接时最好增加默认值。

我仍然希望找到问题第二部分的答案,即有没有办法强制刷新更快。


更新:这甚至是必要的原因是链接表使用与 ADO 传递查询不同的会话。我使用 SQL Profiler 进行了测试。以下是一些简短的结果:

TextData                               SPID
-------------------------------------------
SET IDENTITY_INSERT dbo.TblName ON       50
SET IDENTITY_INSERT "dbo"."TblName" ON   49
exec sp_executesql N'INSERT INTO "d...   49
SET IDENTITY_INSERT dbo.TblName OFF      50
SET IDENTITY_INSERT dbo.NextTbl ON       50
SET IDENTITY_INSERT "dbo"."NextTbl" ON   49
exec sp_executesql N'INSERT INTO "d...   49

这里发生的情况是我的 ADO 命令在与链接表 (#50) 不同的会话 (#49) 中运行。Access 看到我正在为标识列设置值,因此它有助于为该表设置 IDENTITY_INSERT ON。但是,它从不设置 IDENTITY_INSERT OFF。我手动将其关闭,但这是在另一个会话中发生的。

这解释了为什么设置 ODBC 会话超时低有效。这只是一个丑陋的解决方法,因为 Access 一旦打开它就永远不会关闭表上的 IDENTITY_INSERT。由于 IDENTITY_INSERT 是特定于会话的,因此创建新会话就像点击 IDENTITY_INSERT 上的重置按钮。然后 Access 可以为下一个表打开它,并且设置将生效,因为它是一个全新的会话。

于 2011-08-08T21:11:20.083 回答
1

两个想法,虽然不确定是否有用,因为这对我来说是陌生的领域。

MS Access 是否每 10 分钟自动刷新一次它的 ODBC 会话?有没有办法强制它更快地发生?我是否遗漏了一些明显的东西?

在 Access 2003 选项对话框的高级选项卡上,有一个“ODBC 刷新间隔”设置以及重试设置。调整这些是否有帮助......或有任何影响?

我想知道您是否可以通过将 SQL Server 列创建为纯数字而不是自动编号来避免此问题,插入您的数据,然后 ALTER TABLE ... ALTER COLUMN 在插入数据后更改它们。

如果表包含数据,Access 不会让我将数字列转换为自动编号,但 ISTR SQL Server 在这方面更灵活。

于 2011-08-08T20:13:29.987 回答
0

我找到了一个方便但不那么漂亮的解决方案,可以将许多访问表导出到 sql server 并避免 identity_insert 问题:

  1. 我打开一个本地表记录集,其中列出了所有要导出的表,然后循环遍历记录(每个表)。在每个循环中,我...

  2. 创建访问应用程序对象

  3. 在应用程序对象上使用传输数据库方法

  4. 终止/退出应用程序对象并再次循环

这是示例代码:

Public Sub exporttables()
Dim rst As Recordset
Dim access_object

'First create a local access table which lists all tables to be exported'
Set rst = CurrentDb.OpenRecordset("Select txt_tbl from ####your_table_of_tables####")

 With rst
 While Not .EOF
    'generate a new object to avoid identity insert problem'
    Set access_object = CreateObject("Access.Application")
    'with access object open the database which holds the tables to be exported'
    access_object.OpenCurrentDatabase "####C:\yoursourceaccessdb####.accdb"
    access_object.DoCmd.TransferDatabase acExport, "ODBC Database", "ODBC;DSN=####your connection string to target SQL DB;", acTable, .Fields("txt_tbl"), .Fields("txt_tbl"), False, False
    Debug.Print .Fields("txt_tbl") & " exported"
    access_object.CloseCurrentDatabase
    access_object.Application.Quit
    Set access_object = Nothing
    .MoveNext
Wend
End With

Set rst = Nothing
End Sub
于 2022-01-31T16:25:22.653 回答