使用 VBA 中的 SQL 连接来自两个 Excel 工作簿的数据(只读错误)

Using SQL in VBA to Join Data from two Excel Workbooks (Read-Only error)

我想合并两个非常大的 excel 工作簿中的特定数据,然后将其保存到另一个工作簿中。为了做到这一点,我使用 ADODB 对象来使用 SQL 命令,这使得执行连接比执行数十万个 VLookup 更容​​易。我的设置提示一个状态的名称,并且数据源被格式化为依赖于这个状态。假设您输入了 "Nevada"。它将连接到一个名为 "Nevada - biological metadata multiple cont" 的文件,并将其连接到另一个名为 "Nevada - Site data only multiple cont" 的文件和 select 中的某些字段。

当我调试时,我可以看到连接正常工作,并且我将字符串变量 'sql' 更改为等于 "SELECT * FROM [biologicalresult$]" 的地方,它会正常工作。这个问题似乎与我通过 ADODB 查询将它加入另一个工作簿这一事实有关,我收到错误:"Cannot update. Database or object is read-only"

Option Explicit

Sub RunSELECT()

    On Error GoTo ErrorHandling

    Dim cn As Object, rs As Object, output As String, sql As String, state As String
    state = InputBox("Please insert the state name with the first letter being capital")

    Set cn = CreateObject("ADODB.Connection")

    '---Connecting to the Data Source---
    With cn
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .connectionstring = "Data Source=T:\Marketing\Data Analytics\GIS Data\Water Quality Portal Data\State Data\" & state & _
                            " - biological metadata multiple cont;Extended Properties=""Excel 12.0 Xml;HDR=YES;Readonly = false;IMEX = 0"";"
        .Open
    End With

    '---Run the SQL SELECT Query---
    sql = "SELECT b.OrganizationIdentifier, b.OrganizationFormalName, b.MonitoringLocationIdentifier, s.LatitudeMeasure, s.LongitudeMeasure, " & _
        "b.ActivityIdentifier , b.ActivityTypeCode, b.ActivityMediaName, b.ActivityMediaSubdivisionName, " & _
        "b.ActivityStartDate, b.ProjectIdentifier, b.CharacteristicName, b.ResultSampleFractionText, b.ResultMeasureValue, b.[ResultMeasure/MeasureUnitCode] " & _
        "FROM [biologicalresult$] b INNER JOIN (SELECT * FROM [Excel 12.0 Xml; IMEX = 0; HDR = Yes; Database = T:\Marketing\Data Analytics\GIS Data\Water Quality Portal Data\" & _
        "State Data\" & state & " - Site data only multiple cont;Readonly = False].[station$]) s " & _
        "ON b.MonitoringLocationIdentifier = s.MonitoringLocationIdentifier;"

    Set rs = cn.Execute(sql)

    '---Clean up---
    rs.Close
    cn.Close
    Set cn = Nothing
    Set rs = Nothing

Exit Sub

ErrorHandling:
    MsgBox ("Source: " & Err.Source & vbNewLine & "Number: " & Err.Number & vbNewLine & "Description: " & Err.Description & vbNewLine & "Help Context: " & Err.HelpContext)
done:
    End Sub

感谢您的帮助!

诚然,该错误信息量不大,因为问题可能是由于文件路径问题引起的。然而,这个简单的排版修复可能对未来犯同样细微错误的读者有所帮助。顺便说一句,对于长名称,考虑单独的变量并连接成连接和 SQL 字符串。

  1. 在源文件中包含包含扩展名 .xlsx.xlsm 的完整路径。

    meta_file = "T:\Marketing\Data Analytics\GIS Data\Water Quality Portal Data\State Data\" _
                 & state & " - biological metadata multiple cont.xlsx"
    
    With cn
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .connectionstring = "Data Source=" & meta_file & ";Extended Properties=""Excel 12.0 Xml;HDR=YES;Readonly=false;IMEX=0"";"
        .Open
    End With
    
  2. 删除 Database 参数前后的 space 括号名称space: ...Database=T:\Marketing\...。否则,引擎会将 space 解释为名称的一部分。甚至考虑删除所有参数之间的 spaces IMEXHDRReadonly 等。

    site_file = "T:\Marketing\Data Analytics\GIS Data\Water Quality Portal Data\State Data\" _
                 & state & " - Site data only multiple cont.xlsx"
    
    '---Run the SQL SELECT Query---
    sql = "SELECT b.OrganizationIdentifier, b.OrganizationFormalName, " & _
          "       b.MonitoringLocationIdentifier, s.LatitudeMeasure, " & _ 
          "       s.LongitudeMeasure, b.ActivityIdentifier, b.ActivityTypeCode, " & _ 
          "       b.ActivityMediaName, b.ActivityMediaSubdivisionName, " & _
          "       b.ActivityStartDate, b.ProjectIdentifier, b.CharacteristicName, " &  _
          "       b.ResultSampleFractionText, b.ResultMeasureValue, " & _
          "       b.[ResultMeasure/MeasureUnitCode] " & _
          "FROM [biologicalresult$] b " & _
          "INNER JOIN (SELECT * FROM [Excel 12.0 Xml;IMEX=0;HDR=Yes;" & _
          "                           Database=" & site_file & ";Readonly=False].[station$]) s " & _
          "ON b.MonitoringLocationIdentifier = s.MonitoringLocationIdentifier;"