如何避免使用 Access 从 Excel 中的公式导入错误

How to avoid importing errors from formulas in Excel with Access

我有一系列格式相同的电子表格,需要将其导入访问数据库。不幸的是,电子表格数据不是表格形式,所以我需要导入一堆特定的单元格。

我将特定的单元格读取到变量中并构造一个查询以将行插入 table。

当单元格包含等同于错误的公式时,代码失败。为避免错误,我必须插入 Null 而不是错误值。如何插入 Null 而不是错误值?

Public Function ImportSheet()
    Dim xl As Object
    Dim jobno, Address, PM As String
    Dim EDate As Date
    Dim SID As String, SM, SDepth, SCon As String
    Dim SDate As Date
    Dim Sby, SDesc, Tby, Inc, Crack, Crumb As String
    Dim AD1, AD2, AD3, AL1, AL2, AL3 As Double
    Dim SHCID As String
    Dim SHCMass, ILength, IDiam, M0, M1, M2, M3, M4, M5, L0, L1, L2, L3, L4, L5, MC0, MC1, MC2, MC3, MC4, MC5 As Double
    Dim ST0, ST1, ST2, ST3, ST4, ST5, SW0, SW10, SW30, SW1h, SW21h, SW24h, SWih, Esw As Double
    Dim BSWCID As String
    Dim BCMass, BIM, BFM As Double
    Dim ASWCID As String
    Dim ACMass, AIM, AFM, MCI, MCISw, MCFSw, SFS, WD, DD, ISS As Double
        
    Set xl = CreateObject("Excel.Application")
        
    Dim xfileName As Variant
    xfileName = Dir("C:\Users\username\Desktop\Database\Sheets\*.xls")
    
    DoCmd.SetWarnings (False)
    On Error Resume Next
    
    While xfileName <> ""
        With xl.Workbooks.Open(fileName:="C:\Users\username\Desktop\Database\Sheets\" & xfileName)
            With .Sheets("Working Sheet")
                jobno = .Cells(3, "G").Value
                Address = .Cells(3, "C").Value
                PM = .Cells(2, "G").Value
                EDate = .Cells(4, "C").Value
                SID = .Cells(5, "C").Value
                SM = .Cells(6, "C").Value
                SDepth = .Cells(7, "C").Value
                SCon = .Cells(8, "C").Value
                SDate = .Cells(5, "G").Value
                Sby = .Cells(6, "G").Value
                SDesc = .Cells(10, "C").Value
                Tby = .Cells(4, "G").Value
                Inc = .Cells(7, "G").Value
                Crack = .Cells(8, "G").Value
                Crumb = .Cells(9, "G").Value
                AD1 = .Cells(13, "C").Value
                AD2 = .Cells(14, "C").Value
                AD3 = .Cells(15, "C").Value
                AL1 = .Cells(13, "D").Value
                AL2 = .Cells(14, "D").Value
                AL3 = .Cells(15, "D").Value
                SHCID = .Cells(12, "G").Value
                SHCMass = .Cells(13, "G").Value
                ILength = .Cells(14, "G").Value
                IDiam = .Cells(15, "G").Value
                M0 = .Cells(19, "C").Value
                M1 = .Cells(20, "C").Value
                M2 = .Cells(21, "C").Value
                M3 = .Cells(22, "C").Value
                M4 = .Cells(23, "C").Value
                M5 = .Cells(24, "C").Value
                L0 = .Cells(19, "D").Value
                L1 = .Cells(20, "D").Value
                L2 = .Cells(21, "D").Value
                L3 = .Cells(22, "D").Value
                L4 = .Cells(23, "D").Value
                L5 = .Cells(24, "D").Value
                MC0 = .Cells(19, "E").Value
                MC1 = .Cells(20, "E").Value
                MC2 = .Cells(21, "E").Value
                MC3 = .Cells(22, "E").Value
                MC4 = .Cells(23, "E").Value
                MC5 = .Cells(24, "E").Value
                ST0 = .Cells(19, "F").Value
                ST1 = .Cells(20, "F").Value
                ST2 = .Cells(21, "F").Value
                ST3 = .Cells(22, "F").Value
                ST4 = .Cells(23, "F").Value
                ST5 = .Cells(24, "F").Value
                SW0 = .Cells(29, "B").Value
                SW10 = .Cells(30, "B").Value
                SW30 = .Cells(31, "B").Value
                SW1h = .Cells(32, "B").Value
                SW21h = .Cells(33, "B").Value
                SW24h = .Cells(34, "B").Value
                SWih = .Cells(28, "G").Value
                Esw = .Cells(34, "G").Value
                BSWCID = .Cells(43, "F").Value
                BCMass = .Cells(44, "F").Value
                BIM = .Cells(45, "F").Value
                BFM = .Cells(46, "F").Value
                ASWCID = .Cells(43, "G").Value
                ACMass = .Cells(44, "G").Value
                AIM = .Cells(45, "G").Value
                AFM = .Cells(46, "G").Value
                MCI = .Cells(50, "D").Value
                MCISw = .Cells(51, "D").Value
                MCFSw = .Cells(52, "D").Value
                SFS = Abs(.Cells(52, "E").Value)
                WD = .Cells(53, "G").Value
                DD = .Cells(54, "G").Value
                ISS = .Cells(56, "G").Value
                xl.Workbooks(xfileName).Close SaveChanges:=False
            End With
        End With
        On Error GoTo 0
        xfileName = Dir
    Wend
    xfileName = ""
    Set xl = Nothing
    DoCmd.SetWarnings (True)
    
    Dim SQL As String
    SQL = "INSERT INTO Results ( JobNo, Address, PM, EDate, SID, SM, SDepth, SCon, SDate, SBy, SDesc, TBy, Inc, Crack, Crumb, " _
        & "AD1, AD2, AD3, AL1, AL2, AL3, SHCID, SHCMass, ILength, IDiam, M0, M1, M2, M3, M4, M5, L0, " _
        & "L1, L2, L3, L4, L5, MC0, MC1, MC2, MC3, MC4, MC5, ST0, ST1, ST2, ST3, ST4, ST5, SW0, SW10, SW30, SW1h, SW21h, " _
        & "SW24h, SWih, Esw, BSWCID, BCMass, BIM, BFM, ASWCID, ACMass, AIM, AFM, MCI, MCISw, MCFSw, SFS, WD, DD, Iss ) " _
        & "SELECT '" & jobno & "', '" & Address & "', '" & PM & "', #" & EDate & "#, '" & SID & "', '" & SM & "', '" & SDepth & "', '" & SCon & "', #" & SDate & "#, " _
        & "'" & Sby & "', '" & SDesc & "', '" & Tby & "', '" & Inc & "', '" & Crack & "', '" & Crumb & "', '" & AD1 & "', " _
        & "'" & AD2 & "', '" & AD3 & "', '" & AL1 & "', '" & AL2 & "', '" & AL3 & "', '" & SHCID & "', '" & SHCMass & "', " _
        & "'" & ILength & "', '" & IDiam & "', '" & M0 & "', '" & M1 & "', '" & M2 & "', '" & M3 & "', '" & M4 & "', " _
        & "'" & M5 & "', '" & L0 & "', '" & L1 & "', '" & L2 & "', '" & L3 & "', '" & L4 & "', '" & L5 & "', '" & MC0 & "', " _
        & "'" & MC1 & "', '" & MC2 & "', '" & MC3 & "', '" & MC4 & "', '" & MC5 & "', '" & ST0 & "', '" & ST1 & "', '" & ST2 & "', '" & ST3 & "', " _
        & "'" & ST4 & "', '" & ST5 & "', '" & SW0 & "', '" & SW10 & "', '" & SW30 & "', '" & SW1h & "', '" & SW21h & "', " _
        & "'" & SW24h & "', '" & SWih & "', '" & Esw & "',  '" & BSWCID & "', '" & BCMass & "', " _
        & "'" & BIM & "', '" & BFM & "', '" & ASWCID & "', '" & ACMass & "', '" & AIM & "', '" & AFM & "', '" & MCI & "', " _
        & "'" & MCISw & "', '" & MCFSw & "', '" & SFS & "', '" & WD & "', '" & DD & "', '" & ISS & "'"
    
    DoCmd.RunSQL SQL
    MsgBox "Done"
End Function

将变量声明为 Variant 以便能够将 Null 分配给它们。然后,在构造 select 语句时,不要引用这些值,而是在 构造它之前 引用它们:

Dim myvar as Variant
myvar = .Cells(x, y).Value
' We should make sure myvar don't contain apostrophes
myvar = IIf(TypeName(myvar) = "Error", "Null", "'" & myvar & "'")

更好的解决方案是使用 Access 的内置功能来创建新记录,以避免构造格式错误的查询字符串:

Dim myvar As Variant
Dim db As DAO.Database
Dim rs As DAO.Recordset
    ...
Set db = CurrentDb
Set rs = db.OpenRecordset("tablename")
With rs
    .AddNew
    ![FieldName] = IIf(TypeName(myvar) = "Error", Null, myvar)
       ...
    .Update
End With

以这种方式插入时,我们不需要引用我们的值等。

这里是如何修复源代码的精简版。它不仅展示了如何使用 .RunSQL,还展示了 .AddNew。

Option Explicit
Option Compare Database

Public Function ImportCell(myval As Variant)
    If TypeName(myval) = "Error" Then
        ImportCell = Null
    Else
        ImportCell = myval
    End If
End Function

Public Function ToSqlString(myval As Variant) As Variant
    Dim tmp As Variant
    
    tmp = ImportCell(myval)
    If IsNull(tmp) Then
        ToSqlString = "Null"
    Else
        ToSqlString = "'" & myval & "'"
    End If
End Function

Public Function ToSqlDate(myval As Variant) As Variant
    Dim tmp As Variant
    Dim dat As Variant

    tmp = ImportCell(myval)
    If IsNull(tmp) Then
        ToSqlDate = "Null"
        Exit Function
    End If
    On Error Resume Next
    dat = CDate(myval)
    dat = "#" & Format(dat, "yyyy-mm-dd") & "#"
    If Err.Number <> 0 Then
        ToSqlDate = "Null"
        Err.Clear
        Exit Function
    End If
    ToSqlDate = dat
End Function

Public Function ToSqlDouble(myval As Variant) As Variant
    Dim tmp As Variant
    Dim dbl As Double
    
    tmp = ImportCell(myval)
    If IsNull(tmp) Then
        ToSqlDouble = "Null"
        Exit Function
    End If
    On Error Resume Next
    dbl = CDbl(myval)
    If Err.Number <> 0 Then
        ToSqlDouble = "Null"
        Err.Clear
        Exit Function
    End If
    ToSqlDouble = dbl
End Function

Public Sub ImportSheet()
    Dim path As String
    Dim filename As Variant
    Dim app As Object
    Dim wbk As Object
    Dim sht As Object
    Dim JobNo As Variant ' String
    Dim SDate As Variant ' Date
    Dim M1 As Variant ' Double
    Dim query As String
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    
    Set db = CurrentDb
    Set rs = db.OpenRecordset("Results")

    Set app = CreateObject("Excel.Application")
    path = "C:\Users\username\Desktop\Database\Sheets\"
    filename = Dir(path & "*.xls")
    DoCmd.SetWarnings False
    app.Visible = True
    While filename <> ""
        ' Get row data from the workbook
        Set wbk = app.Workbooks.Open(filename:=path & filename)
        Set sht = wbk.Sheets("Working Sheet")
        ' Debugging data: sht.Range(sht.cells(1, 1), sht.cells(100, 100)) = "=ROW() & ""x"" & COLUMN()"
        If False Then
            ' Use DoCmd.RunSQL
            JobNo = ToSqlString(sht.cells(3, 5)) ' string
            SDate = ToSqlDate(sht.cells(5, 5)) ' date
            M1 = ToSqlDouble(sht.cells(20, 3)) ' double
            ' Insert the row into the table
            query = "INSERT INTO Results ( JobNo, SDate, M1 ) " & _
                    "SELECT " & JobNo & ", " & SDate & ", " & M1 & " "
            'Debug.Print query
            DoCmd.RunSQL query
        Else
            ' Use RecordSet.AddNew
            With rs
                .AddNew
                ' The excel cells must contain the expected  type of data.
                ' The type can be checked, using a technique similar (but simpler) to the ones used by the ToSqlXXXX-methods
                ![JobNo] = ImportCell(sht.cells(3, 5))
                ![SDate] = ImportCell(sht.cells(5, 5))
                ![M1] = ImportCell(sht.cells(20, 3))
                .Update
            End With
        End If
        wbk.Close SaveChanges:=False
        ' Get the next filename
        filename = Dir
    Wend
    DoCmd.SetWarnings True
    MsgBox "Done"
End Sub

我建议您从 sheet 中读取一个范围,将您需要的所有单元格包含到一个数组中,而不是多次引用 sheet。参见: