为什么这个用于CSV文件的SQL查询的VBA代码会间歇性地工作?

时间:2016-10-29 18:37:53

标签: sql excel vba csv ado

一个非常简单的查询函数,它接收源CSV文件的路径和作为字符串的SQL语句(我也是从VBA函数转置数据),

Public Function RunQuery(FilePath As String, SQLStatement As String)

    Dim Conn As New ADODB.Connection
    Dim RecSet As New ADODB.Recordset

    With Conn
        .Provider = "Microsoft.Jet.OLEDB.4.0"
        .ConnectionString = "Data Source=" & FilePath & ";" & _
        "Extended Properties=""text;HDR=Yes;FMT=Delimited;IMEX=1"""
    End With

    Conn.Open
    RecSet.Open SQLStatement, Conn
    RecSet.MoveFirst
    RunQuery = RecSet.GetRows()

    Conn.Close
    Set RecSet = Nothing
    Set Conn = Nothing

End Function

此代码对CSV文件间歇性地工作,一些数据被正确检索而一些数据没有。

这两个CSV文件就是一个例子 - AbbreviatedFull。以下SQL查询在缩写文件上完美运行,但在完整文件中返回#VALUE。

SELECT birthYear FROM [File]

这绝对不是数据限制/大小问题,因为Full文件只包含1800行。我完全被迷惑了,并会感激任何想法/指示。

顺便说一句,如果我将逻辑包装成Sub而不是UDF,那么它可以完美地运行而不会出现任何错误,

Public Sub RunQuerySub()

Dim Conn As New ADODB.Connection
Dim RecSet As New ADODB.Recordset
Dim FilePath As String
FilePath = ActiveSheet.Range("Path")

With Conn
    .Provider = "Microsoft.Jet.OLEDB.4.0"
    .ConnectionString = "Data Source=" & FilePath & ";" & _
    "Extended Properties=""text;HDR=Yes;FMT=Delimited;IMEX=1"""
End With
Dim SQLStatement As String
SQLStatement = ActiveSheet.Range("SQL")

Conn.Open
RecSet.Open SQLStatement, Conn
ActiveSheet.Cells(1, 8).CopyFromRecordset RecSet

Conn.Close
Set RecSet = Nothing
Set Conn = Nothing

End Sub

我很困惑,并且会感激任何指示。

3 个答案:

答案 0 :(得分:0)

当我建议从Sub运行它时,我并不是说 as 是Sub。

我的意思是做类似下面的事情,你的功能没有改变,唯一的区别是你是从VBA而不是UDF运行它。

从VBA运行时,您将能够看到任何错误,而不仅仅是在工作表单元格中获取#VALUE。

Sub Tester()
    Dim arr
    arr = RunQuery("yourPath", "yourSQL")
End sub


Public Function RunQuery(FilePath As String, SQLStatement As String)

    Dim Conn As New ADODB.Connection
    Dim RecSet As New ADODB.Recordset

    With Conn
        .Provider = "Microsoft.Jet.OLEDB.4.0"
        .ConnectionString = "Data Source=" & FilePath & ";" & _
        "Extended Properties=""text;HDR=Yes;FMT=Delimited;IMEX=1"""
    End With

    Conn.Open
    RecSet.Open SQLStatement, Conn
    RecSet.MoveFirst
    RunQuery = RecSet.GetRows()

    Conn.Close
    Set RecSet = Nothing
    Set Conn = Nothing

End Function

答案 1 :(得分:0)

此按钮单击事件处理程序通过调用RunQuerySub生成结果。在B2,B3中定义了三个输入参数。 B4。

Sub Button1_Click()
    Dim FilePath As String, SQLStatement As String, TargetColumn As String
    FilePath = Sheet1.Range("B2").Text
    SQLStatement = Sheet1.Range("B3").Text
    TargetColumn = Sheet1.Range("B4").Text
    Call RunQuerySub(FilePath, SQLStatement, TargetColumn)
End Sub

子程序和你一样,但有一些Null值导致分配给Range对象的问题,所以我用零替换它们。 RecSet.GetRows()的结果集是一个2D变体数组,其第二维中的birthYear值。我将这些值分配给一个数组,其中的值在第一个维度中,因此它将按行填充范围。

功能似乎不允许您为范围指定值 - 无论如何我无法找到方法。

Public Sub RunQuerySub(FilePath As String, SQLStatement As String, TargetColumn As String)

    Dim Conn As New ADODB.Connection
    Dim RecSet As New ADODB.Recordset
    Dim rows As Variant
    On Error GoTo ErrHandler
    With Conn
        .Provider = "Microsoft.Jet.OLEDB.4.0"
        .ConnectionString = "Data Source=" & FilePath & ";" & _
        "Extended Properties=""text;HDR=Yes;FMT=Delimited;IMEX=1"""
    End With

    Conn.Open
    RecSet.Open SQLStatement, Conn
    RecSet.MoveFirst
    rows = RecSet.GetRows()

    Conn.Close
    Set RecSet = Nothing
    Set Conn = Nothing

    Dim dest As Range
    Dim nrows As Integer, i As Integer, valu As Integer
    nrows = UBound(rows, 2) + 1
    ReDim arr2(1 To nrows, 1 To 1) As Integer
    For i = 1 To nrows
        If IsNull(rows(0, i - 1)) Then
            valu = 0
        Else
            valu = rows(0, i - 1)
        End If
        arr2(i, 1) = valu
    Next
    Dim rangeDefn As String
    rangeDefn = TargetColumn & "1:" & TargetColumn & CStr(nrows)
    With ThisWorkbook.Sheets("Sheet1")
        Set dest = .Range(rangeDefn)
    End With
    dest = arr2
    Exit Sub

ErrHandler:
    Debug.Print Err.Number, Err.Description
    Resume Next
End Sub

答案 2 :(得分:0)

我改编了使用Article::withCount('comments')->orderBy('comments_count')->get(); 的技术并设法获得了withCount(),它返回了缩写文件和完整文件的数组。

在列中突出显示1892个细胞的范围。使用此数组函数

Sub

这是功能。它将结果集中的Function值替换为零。

=RunQuery("C:\stackoverflow", "SELECT birthYear FROM [full.csv]")