从CSV读取双打时出现问题-VBA

时间:2019-01-13 21:23:41

标签: excel vba csv adodb

我想从vba-excel中读取一个csv文件,但是我有一个双精度值的问题,例如,在csv中此值:125.5读取时不带点。所以我得到1255。 我的代码:

Dim rs As New ADODB.Recordset
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & myDir & ";" & "Extended Properties=""text;HDR=Yes;FMT=Delimited()"";"
strSQL = "SELECT * FROM " & myFileName
rs.Open strSQL, strCon, 3, 3
IBH = rs("IBH")

我该如何解决?

更新: 我尝试了@Siddharth Rout解决方案,但是我仍然遇到相同的问题。 现在我的代码:

Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim myDate, myTime, IBH, IBL
Dim myDir As String, myFileName As String
Dim strSQL As String

myDir = Trim(shParams.Range("fp_path"))
myFileName = Trim(shParams.Range("fp_filename"))

With conn
 .Provider = "Microsoft.ACE.OLEDB.12.0"
 .ConnectionString = "Data Source=" & myDir & ";Extended Properties='text'"
 .Open
End With

strSQL = "SELECT * FROM " & myFileName
rs.Open strSQL, conn, 3, 3
rs.MoveLast

myDate = rs("Date")
myTime = rs("Time")
IBH = rs("IBH")
IBL = rs("IBL")

Debug.Print myDate, myTime, IBH, IBL

rs.Close
Set rs = Nothing

这是结果:

enter image description here 这是我的csv:

enter image description here

2 个答案:

答案 0 :(得分:2)

此问题源于ACE引擎如何确定ADODB字段的类型。驱动程序将扫描一定数量的行,以确定整个列的类型。

更改连接字符串


您可以尝试做的一件事是将连接字符串中的MaxScanRows更改为0。将该值设置为0将扫描所有行以确定类型,请记住,这可能会对性能产生影响,具体取决于数据集的大小。

";Extended Properties='text;MaxScanRows=0;IMEX=0'"

这并不总是能给您想要的结果。假设我们有一个这样的数据集:

+--------------------------+
|       DoubleField        |
+--------------------------+
| 1                        |
| 2                        |
| 3                        |
| ...(996 more records...) |
| 1000.01                  |
+--------------------------+

驱动程序将查看并看到999个看起来像整数的记录和1个看起来像一个Double的记录。它将基于MajorityType决定此字段是整数,而不是双精度数。坦白地说,我不确定该类型确定是如何准确完成的,但这确实符合这些原则。我还看到过一些实例,只需将顶部记录更改为所需的类型即可。例如

+--------------------------+
|       DoubleField        |
+--------------------------+
| 1.00                     |
| 2                        |
| 3                        |
| ...(996 more records...) |
| 1000.01                  |
+--------------------------+

因此,另一种方法可能是格式化源文件,使其预先包含小数位。如果您控制源文件,这应该很容易做到,但这并非总是如此。

使用架构INI文件


如果无法提高MaxScanRows,请确保使用 Commintern 所指出的Schema.ini文件来获得期望的每一列类型。

>

这里是link的内容。

要点是,制作一个文件,为每个列显式定义每种类型。对于我们上面设计的表格,它变为:

[MyFileNameGoesHere.csv]
ColNameHeader = True
Format = CSVDelimited
Col1=DoubleField Double

然后,您将此文件另存为Schema.Ini,并将其放置在与要导入的文件相同的目录中。这种方法的好处在于,它只是创建一个文本文件,您甚至可以在VBA中完成此操作而不会遇到太多麻烦。这种方法的缺点是,如果要导入很多文件,则很难管理所有Schema.ini文件。

纯粹的VBA方法


您可以在ADODB中创建一个内存中表,并使用csv文件中的数据填充该表。这是一个小代码示例,可以帮助您入门。

Option Explicit

Private Function getTypedRS() As ADODB.Recordset
    Set getTypedRS = New ADODB.Recordset

    With getTypedRS
        'Add your other fields here
        .Fields.Append "DoubleField", adDouble
    End With
End Function

Public Sub CSVToADODB()
    Dim myTimer         As Double
    Dim FileNumber      As Long
    Dim FilePath        As String
    Dim FileData        As String
    Dim CSVArray        As Variant
    Dim i               As Long
    Dim rs              As ADODB.Recordset

    myTimer = Timer
    Set rs = getTypedRS()
    FilePath = "C:\Users\Ryan\Desktop\Example.csv"

    'Get the CSV
    FileNumber = FreeFile()
    Open FilePath For Binary Access Read As FileNumber
    FileData = Space$(LOF(FileNumber)) 'Create a buffer first, then assign
    Get FileNumber, , FileData
    Close FileNumber

    'My CSV is just a list of Doubles, should be relatively easy to swap out to process with ','
    CSVArray = Split(FileData, vbCrLf)

    'Add data
    rs.Open
    For i = LBound(CSVArray) + 1 To UBound(CSVArray) '+1 to skip header
        rs.AddNew
        rs.Fields("DoubleField").Value = CSVArray(i)
    Next
    rs.UpdateBatch
    rs.MoveLast

    Debug.Print rs.Fields("DoubleField").Value, "Processed 1000 records in: " & Timer - myTimer
End Sub

这种方法的优点在于它仍然相当快。我能够在约0.03秒内加载1000个双音,因为此处完成的大多数操作都是在内存中完成的。这也避免了对Schema.ini文件的需要,但是需要维护更多代码,因此这是一个折衷方案。

推荐


我会尝试更改MaxScanRows,如果不起作用,请创建Schema.ini文件。

答案 1 :(得分:0)

尝试一下

Sub Sample()
    Dim conn As New ADODB.Connection
    Dim RS As New ADODB.Recordset

    Dim FilePath As String, SheetName As String

    '~~> Replace this with relevant values
    FilePath = "C:\Users\routs\Desktop"
    Filename = "Sample.Csv"

    With conn
       .Provider = "Microsoft.ACE.OLEDB.12.0"
       .ConnectionString = "Data Source=" & FilePath & ";Extended Properties='text'"
       .Open
    End With

    strSQL = "select * from " & Filename

    RS.Open strSQL, conn

    '~~> Replace this with relevant field
    Debug.Print RS("Sale")
End Sub

enter image description here