【问题标题】:Bulk insert records into Access using Vbscript使用 Vbscript 将记录批量插入 Access
【发布时间】:2011-07-04 17:30:38
【问题描述】:

我真的用这个把头发拉出来了。我有一个 vbscript,我正在尝试将几十万条记录插入 Access 数据库。

显然,如果我一次只做一个,这真的很慢,所以我想我可以通过某种事务批量插入它们。所以我试着写这个:

set rs = CreateObject("ADODB.recordset")
 rs.Open "table", objConn,, 4

For counter = 1 to 100000
  rs.AddNew
  rs("username") = "Value"
Next

  rs.UpdateBatch

(objConn是数据库连接)。

问题是我收到一条错误消息:

“未决更改的行数超出限制”

当有多个未决更改时,我会明白这一点。

我想我的交易设置不正确,但我有点卡住了。不要以为有人可以指出我的方式的错误吗?非常感谢。

【问题讨论】:

  • 你从哪里得到记录?外部来源(文件?)?还是你在内存中生成它们?
  • 它们是在内存中生成的。如果您认为这会有所帮助,我可以先将它们写入文件,但这感觉不是做这类事情的正确方法。

标签: ms-access vbscript ado


【解决方案1】:

为了支持我在事务中使用命令的提议,我写道 这个脚本:

  Dim sAct      : sAct      = "trout"
  If goWAN.Exists( "a" ) Then sAct = goWAN( "a" )
  Dim nRecs     : nRecs     = 10
  If goWAN.Exists( "n" ) Then nRecs = CLng( goWAN( "n" ) )
  Dim sMFSpec   : sMFSpec   = goFS.GetAbsolutePathName( "..\data\ut.mdb" )
  Dim oConn     : Set oConn = CreateObject( "ADODB.Connection" )
  Dim oRs       : Set oRs   = CreateObject( "ADODB.Recordset" )

  Dim nRec, oCmd, nRA, aData, oParm

  oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & sMFSpec
  Set oRs.ActiveConnection = oConn

  oConn.Execute( "DELETE FROM tLines" )
  WScript.Echo "#Recs:", oConn.Execute( "SELECT COUNT(SampleText) FROM tLines" ).Fields( 0 )

  WScript.Echo sAct
  Select Case sAct
    Case "trout"
    Case "bob"
      oRs.CursorLocation = adUseClient
      oRs.CursorType = adOpenKeySet
      oRs.LockType = adLockBatchOptimistic    
    Case "eh"  
  End Select
  WScript.Echo "oRs.CursorLocation: ", oRs.CursorLocation
  WScript.Echo "oRs.CursorType: ", oRs.CursorType
  WScript.Echo "oRs.LockType: ", oRs.LockType
  Select Case sAct
    Case "trout", "bob"
      oRs.Open "tLines", oConn, , adLockBatchOptimistic
      For nRec = 1 to nRecs
          oRs.AddNew
          oRs( "SampleText" ) = "This is line " & nRec
      Next
      oRs.UpdateBatch
      oRs.Close
    Case "eh" 
      oConn.BeginTrans
      Set oParm = CreateObject( "ADODB.Parameter" )
      With oParm
        .Name      = "A"
        .Type      = adVarChar
        .Value     = ""
        .Direction = adParamInput
        .Size      = 100
      End With
      Set oCmd = CreateObject( "ADODB.Command" )
      With oCmd
        Set .ActiveConnection = oConn
            .CommandText      = "INSERT INTO tLines (SampleText) VALUES (?)"
            .CommandType      = adCmdText
            .Parameters.Append oParm
      End With

      ReDim aData( 0 )
      For nRec = 1 to nRecs
          aData( 0 ) = "This is line " & nRec
          oCmd.Execute nRA, aData, adExecuteNoRecords + adCmdText
      Next
      oConn.CommitTrans 
  End Select

  WScript.Echo "#Recs:", oConn.Execute( "SELECT COUNT(SampleText) FROM tLines" ).Fields( 0 )
  WScript.Echo "First:", oConn.Execute( "SELECT TOP 1 * FROM tLines" ).Fields( 0 )

  oConn.Close

用 /n:200 和 /a:trout 调用它显示:

  #Recs: 0
  trout
  oRs.CursorLocation:  2
  oRs.CursorType:  0
  oRs.LockType:  1
  ... xpl.vbs(246, 11) Provider: Number of rows with pending changes exceeded the limit.

所以我认为,我正确地重现了您的问题。对于 /a:bob:

  #Recs: 0
  bob
  oRs.CursorLocation:  3
  oRs.CursorType:  1
  oRs.LockType:  4
  #Recs: 200
  First: This is line 1
  xpl.vbs: Erfolgreich beendet. (0) [ 19.74219 secs ]

所以设置

  oRs.CursorLocation = adUseClient
  oRs.CursorType = adOpenKeySet
  oRs.LockType = adLockBatchOptimistic    

正如 Bob(和 Microsoft)所建议的那样,这是解决您问题的一种方法。为了获得一些速度,我放了一个 命令进入事务:

  oConn.BeginTrans
  Set oCmd = CreateObject( "ADODB.Command" )
  ...
  ReDim aData( 0 )
  For nRec = 1 to nRecs
      aData( 0 ) = "This is line " & nRec
      oCmd.Execute nRA, aData, adExecuteNoRecords + adCmdText
  Next
  oConn.CommitTrans 

结果:

#Recs: 0
eh
oRs.CursorLocation:  2
oRs.CursorType:  0
oRs.LockType:  1
#Recs: 200
First: This is line 1
xpl.vbs: Erfolgreich beendet. (0) [ 1.47656 secs ]

从 20 到 2 秒(没有任何属性摆弄)对我来说似乎不错。

【讨论】:

  • 哦,太棒了!非常感谢。非常感谢您为此付出的努力。我的脚本已经不再需要很长时间,我可以泡一杯茶然后回来,它仍然会运行到大约 5 秒。
【解决方案2】:

如果您使用的是 OLEDB,则需要根据以下知识库文章将 CursorLocation 属性设置为 adUseClient:http://support.microsoft.com/kb/261297

如果一次运行 100k 速度很慢,您也可以考虑小批量运行

编辑:是的,adUseClient 需要定义为 = 3,或者只使用数字 3。

【讨论】:

  • 所以我看到了那篇文章,并尝试添加:rs.CursorLocation = adUseClient 但我收到一条错误消息,提示“参数类型错误、超出可接受范围或在相互冲突”,我无法弄清楚是什么原因造成的。
  • 实际上,我认为这可能是答案,但由于某种原因“rs.CursorLocation = adUseClient”不起作用,我必须使用“rs.CursorLocation = 3”——让我来测试一下...
  • 也许考虑在数据库中触发一堆插入语句而不是使用记录集对象?
猜你喜欢
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 2019-05-10
  • 1970-01-01
相关资源
最近更新 更多