使用ACE OLEDB Engine读取csv数据,如何检测数据中的错误
Read csv data with ACE OLEDB Engine, how to detect errors in data
在 Excel VBA 中,我尝试使用 ACE OLEDB 引擎和 schema.ini 文件读取 CSV 文本文件。这行得通,但是当数据出现错误时,我预计 ACE OLEDB 引擎会抛出异常。
但是,它只是将数据中的错误值读取为 null,将它们作为空值传递,并且它只是继续而没有任何错误消息。尤其是对于大型数据集,这是行不通的,因为无法手动轻松发现任何错误。
这是一个制表符分隔的数据集,为了重现它存在一些故意的错误。
OrderID OrderDate Amount Price ArtNo
40361 07/09/2019 2 59.95 4006633374668
40362 07/10/2019 2 42,95 4006633146647
40363 07/11/2019 1 69.75 4016987119501
40364 07/12/2019 4 4.99 4082300264630
40365 07/13/2019 1 39.95 4026736081348
40366 07/14/2019 1 230.00 4013872786831
40367 07/29/2019 1 42.95 4006633294256
40368 07/30/2019 1 3,299.00 GTIN:0191215072422
40369 07/31/2019 1 86.95 4010858791506
40370 07/32/2019 10 8.99 4029416288686
以及对应的schema.ini文件
[testdata.txt]
DateTimeFormat=m/d/yyyy
DecimalSymbol=.
Format=TabDelimited
Col1=OrderID Integer Width 5
Col2=OrderDate Date Width 10
Col3=Amount Integer Width 2
Col4=Price Float Width 10
Col5=ArtNo Text Width 13
使用 ACE OLEDB 连接到文本数据文件并执行 SELECT * FROM textfile
结果是这样的:
有些单元格是空的,即使数据文件中有值。
B: 值 "42,95" 是一个错误 DecimalSymbol
被设置为 point.
D: 值 "3,299.00" 是一个错误,因为千位逗号
E: 值“07/32/2019”是不正确的日期
F*:值 "GTIN:0191215072422" 太长,E9 在 13 个字符处截断(*未在图像中标记)
(顺便说一句,日期值 A 也被错误地解释,即使设置 DateTimeFormat=m/d/yyyy
是正确的,但 C 是正确的可能只是因为日期高于 12,但 Excel 总是烦躁不安的日期格式所以我会在这里忽略那些)
下面是使用 ACE OLEDB 引擎加载文本数据文件的 VBA 代码。
Sub ReadCsvTest(sPath As String, sFile As String, sBOM As String)
Dim Wsh As Worksheet
Dim AdoConnect As ADODB.Connection ' Tools > References > select "Microsoft ActiveX Data Objects x.x Library"
Dim AdoRcrdSet As ADODB.Recordset
Dim strSQL As String
Dim sField As String
Dim sValue As String
Dim i As Integer
Dim iRow As Integer
' not sure what it does, but just set sBOM = "\xEF\xBB\xBF"
' Add a new sheet
With ActiveWorkbook
Set Wsh = .Sheets.Add(After:=.Sheets(.Sheets.Count))
'Wsh.Name = NewSheetName 'rename new Sheet
End With
Set AdoConnect = New ADODB.Connection
AdoConnect.Provider = "Microsoft.ACE.OLEDB.12.0"
AdoConnect.ConnectionString = "Data Source=" & sPath & ";Extended Properties='text';"
AdoConnect.Open
strSQL = "select * from " & sFile
Set AdoRcrdSet = New ADODB.Recordset
AdoRcrdSet.Open strSQL, AdoConnect
' header column names
For i = 0 To AdoRcrdSet.Fields.Count - 1
sField = WorksheetFunction.Substitute(AdoRcrdSet.Fields(i).Name, sBOM, "")
Wsh.Cells(1, i + 1).Value = sField
Next
' row values
iRow = 2
AdoRcrdSet.MoveFirst
While Not AdoRcrdSet.EOF
For i = 0 To AdoRcrdSet.Fields.Count - 1
sValue = IIf(IsNull(AdoRcrdSet.Fields(i).Value), "", AdoRcrdSet.Fields(i).Value)
Wsh.Cells(iRow, 1 + i).Value = sValue
Next
AdoRcrdSet.MoveNext
iRow = iRow + 1
Wend
End Sub
顺便说一句,我知道我也可以使用“打开文件”对话框并手动设置每列的数据类型和格式,但这完全忽略了 schema.ini。而且,对于其他用途,需要使用 ACE OLEDB 引擎。
所以我的问题是,是否可以检测到这些类型的数据错误?
我能以某种方式区分数据错误和实际 empty/null 值吗?
或者我可以在连接字符串中使用一个额外的设置来使 ACE OLEDB 引擎抛出错误,或者让它将错误值设置为 null 以外的值吗?
对于任何对此问题感兴趣的人,我最终创建了一个 CSV Lint plug-in for Notepad++。
插件可以自动检测csv的类型(逗号、制表符等)和列的数据类型。此数据定义基于 schema.ini 格式。然后插件可以根据此元数据验证数据。
自动列检测大部分时间都有效,它并不总是能正确检测数据类型。但是,您可以在验证数据文件之前手动编辑元数据,所以这应该不是问题。它也适用于固定宽度的数据文件,它包括一个语法高亮选项,如您在屏幕截图中所见。
我希望用附加功能更新这个 Notepad++ 插件,但它非常适合检测 csv 文件中的数据错误。
您可以在这里获取插件:
http://github.com/BdR76/CSVLint
在 Excel VBA 中,我尝试使用 ACE OLEDB 引擎和 schema.ini 文件读取 CSV 文本文件。这行得通,但是当数据出现错误时,我预计 ACE OLEDB 引擎会抛出异常。
但是,它只是将数据中的错误值读取为 null,将它们作为空值传递,并且它只是继续而没有任何错误消息。尤其是对于大型数据集,这是行不通的,因为无法手动轻松发现任何错误。
这是一个制表符分隔的数据集,为了重现它存在一些故意的错误。
OrderID OrderDate Amount Price ArtNo
40361 07/09/2019 2 59.95 4006633374668
40362 07/10/2019 2 42,95 4006633146647
40363 07/11/2019 1 69.75 4016987119501
40364 07/12/2019 4 4.99 4082300264630
40365 07/13/2019 1 39.95 4026736081348
40366 07/14/2019 1 230.00 4013872786831
40367 07/29/2019 1 42.95 4006633294256
40368 07/30/2019 1 3,299.00 GTIN:0191215072422
40369 07/31/2019 1 86.95 4010858791506
40370 07/32/2019 10 8.99 4029416288686
以及对应的schema.ini文件
[testdata.txt]
DateTimeFormat=m/d/yyyy
DecimalSymbol=.
Format=TabDelimited
Col1=OrderID Integer Width 5
Col2=OrderDate Date Width 10
Col3=Amount Integer Width 2
Col4=Price Float Width 10
Col5=ArtNo Text Width 13
使用 ACE OLEDB 连接到文本数据文件并执行 SELECT * FROM textfile
结果是这样的:
有些单元格是空的,即使数据文件中有值。
B: 值 "42,95" 是一个错误 DecimalSymbol
被设置为 point.
D: 值 "3,299.00" 是一个错误,因为千位逗号
E: 值“07/32/2019”是不正确的日期
F*:值 "GTIN:0191215072422" 太长,E9 在 13 个字符处截断(*未在图像中标记)
(顺便说一句,日期值 A 也被错误地解释,即使设置 DateTimeFormat=m/d/yyyy
是正确的,但 C 是正确的可能只是因为日期高于 12,但 Excel 总是烦躁不安的日期格式所以我会在这里忽略那些)
下面是使用 ACE OLEDB 引擎加载文本数据文件的 VBA 代码。
Sub ReadCsvTest(sPath As String, sFile As String, sBOM As String)
Dim Wsh As Worksheet
Dim AdoConnect As ADODB.Connection ' Tools > References > select "Microsoft ActiveX Data Objects x.x Library"
Dim AdoRcrdSet As ADODB.Recordset
Dim strSQL As String
Dim sField As String
Dim sValue As String
Dim i As Integer
Dim iRow As Integer
' not sure what it does, but just set sBOM = "\xEF\xBB\xBF"
' Add a new sheet
With ActiveWorkbook
Set Wsh = .Sheets.Add(After:=.Sheets(.Sheets.Count))
'Wsh.Name = NewSheetName 'rename new Sheet
End With
Set AdoConnect = New ADODB.Connection
AdoConnect.Provider = "Microsoft.ACE.OLEDB.12.0"
AdoConnect.ConnectionString = "Data Source=" & sPath & ";Extended Properties='text';"
AdoConnect.Open
strSQL = "select * from " & sFile
Set AdoRcrdSet = New ADODB.Recordset
AdoRcrdSet.Open strSQL, AdoConnect
' header column names
For i = 0 To AdoRcrdSet.Fields.Count - 1
sField = WorksheetFunction.Substitute(AdoRcrdSet.Fields(i).Name, sBOM, "")
Wsh.Cells(1, i + 1).Value = sField
Next
' row values
iRow = 2
AdoRcrdSet.MoveFirst
While Not AdoRcrdSet.EOF
For i = 0 To AdoRcrdSet.Fields.Count - 1
sValue = IIf(IsNull(AdoRcrdSet.Fields(i).Value), "", AdoRcrdSet.Fields(i).Value)
Wsh.Cells(iRow, 1 + i).Value = sValue
Next
AdoRcrdSet.MoveNext
iRow = iRow + 1
Wend
End Sub
顺便说一句,我知道我也可以使用“打开文件”对话框并手动设置每列的数据类型和格式,但这完全忽略了 schema.ini。而且,对于其他用途,需要使用 ACE OLEDB 引擎。
所以我的问题是,是否可以检测到这些类型的数据错误? 我能以某种方式区分数据错误和实际 empty/null 值吗? 或者我可以在连接字符串中使用一个额外的设置来使 ACE OLEDB 引擎抛出错误,或者让它将错误值设置为 null 以外的值吗?
对于任何对此问题感兴趣的人,我最终创建了一个 CSV Lint plug-in for Notepad++。
插件可以自动检测csv的类型(逗号、制表符等)和列的数据类型。此数据定义基于 schema.ini 格式。然后插件可以根据此元数据验证数据。
自动列检测大部分时间都有效,它并不总是能正确检测数据类型。但是,您可以在验证数据文件之前手动编辑元数据,所以这应该不是问题。它也适用于固定宽度的数据文件,它包括一个语法高亮选项,如您在屏幕截图中所见。
我希望用附加功能更新这个 Notepad++ 插件,但它非常适合检测 csv 文件中的数据错误。
您可以在这里获取插件:
http://github.com/BdR76/CSVLint