【问题标题】:Functions to convert SQL into VBA strings将 SQL 转换为 VBA 字符串的函数
【发布时间】:2014-04-04 03:30:35
【问题描述】:

我在一张 Excel 表格中构建了数百个 SQL 查询,每个查询都放在一个 1 列的单元格中。我要做的是从 excel 中运行这些 SQL 语句。

只是想知道是否有人知道将我的所有 SQL 转换为 VBA 字符串的方法,以便我可以遍历所有行以运行每个查询。

我发现这是我想要做的,但有没有办法可以更改代码,以便它可以读取 excel 单元格而不是表单?

http://allenbrowne.com/ser-71.html

谢谢

编辑:这是我尝试转换的示例 SQL

SELECT 
TT.TEST_TABLE_ID,
TT.TEST_TABLE_NO,
TT.MEMBERSHIP_NUMBER,
TT.TEST_TABLE_TYPE,
from TEST_TABLE TT

我认为因为每个 Select 都在自己的行中,所以在转换时会导致问题。

编辑 #2:这是我执行 SQL 的代码

Sub GetData()
Dim Conn As New ADODB.Connection
Dim RS As New ADODB.Recordset
Dim cmd As New ADODB.Command
Dim sqlText As String
Dim Row As Long
Dim Findex As Long
Dim Data As Worksheet
Dim X As Long
    Set Data = Sheets("Results")
    Data.Select
    Cells.ClearContents
    Conn.Open "PROVIDER=ORAOLEDB.ORACLE;DATA SOURCE=ORCL;USER ID=user;PASSWORD=password"
    cmd.ActiveConnection = Conn
    cmd.CommandType = adCmdText
    'sqlText = How to reference Valid SQL cells
    cmd.CommandText = sqlText
    Set RS = cmd.Execute
    For X = 1 To RS.Fields.Count
        Data.Cells(1, X) = RS.Fields(X - 1).Name
    Next

    If RS.RecordCount < Rows.Count Then
        Data.Range("A2").CopyFromRecordset RS
    Else
        Do While Not RS.EOF
           Row = Row + 1
           For Findex = 0 To RS.Fields.Count - 1
             If Row >= Rows.Count - 50 Then
                Exit For
             End If
             Data.Cells(Row + 1, Findex + 1) = RS.Fields(Findex).Value
           Next Findex
           RS.MoveNext
        Loop
    End If
    Cells.EntireColumn.AutoFit
End Sub

在 SQL 文本部分,我希望能够引用我拥有的 SQL 语句列。我想我需要转换它,但你们是对的,如果引用它,我可以使用你的代码 Brad。

我尝试将您的代码 brad 合并到我的 'sqlText = How to reference Valid SQL cells 所在的位置,但没有成功

【问题讨论】:

  • 你已经在开头和结尾加上引号了吗?
  • 不,我没有,但如果它更容易我可以添加
  • 如果您可以从其中一个单元格中复制 SQL 并在查询工具中运行它,则无需任何额外的格式化,只需从单元格中读取 SQL 并直接在您的 VBA 中执行即可.如果您认为需要一些额外的格式,您应该准确解释它是什么,并提供示例。您发布的链接是关于在 VBA 源代码中包含 SQL,而不仅仅是执行该 SQL 所必需的。从您当前的帖子中,@Brad 的回答已经提供了解决方案。
  • 是的,抱歉,这就是我不清楚的地方。我有一个有效的 SQL 语句,我正在尝试在需要格式更改的 VBA 源代码中执行此 SQL 语句
  • 是的,我希望将结果返回给我。没有插入/更新/删除它更多的是验证以查看数据是否存在,因此只需选择

标签: sql vba excel


【解决方案1】:

这是我认为您需要的代码的开始。

我已将 SQL 放在 Col A 中名为“SQL”的工作表中。 与此相关的问题是: (1) 您将字段名称放在一行中,然后将返回的数据放在一行中。这将需要每个 SQL 语句两行。 (2)我从表“SQL”复制SQL语句并放在“结果”的A列(你提到你想把结果放在SQL字符串的右边。(3)你清除了“结果”表的内容,所以如果您决定合并工作表,则需要注意不要删除您的 SQL。

Option Explicit

Sub Process_SQL_Strings()
Dim cmd         As New ADODB.Command
Dim sqlText     As String
Dim Row         As Long
Dim Findex      As Long
Dim Data        As Worksheet
Dim iFldCt      As Long
Dim conn        As ADODB.Connection
Dim rs          As ADODB.Recordset
Dim sConn       As String
Dim lLastRow    As Long
Dim lRow        As Long

    Set Data = Sheets("Results")
    Data.Select
    Cells.ClearContents
    conn.Open "PROVIDER=ORAOLEDB.ORACLE;DATA SOURCE=ORCL;USER ID=user;PASSWORD=password"
    cmd.ActiveConnection = conn
    cmd.CommandType = adCmdText

''        Set conn = New ADODB.Connection
''        sConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
''                                 "Data Source=C:\data\access\tek_tips.accdb;" & _
''                                 "Jet OLEDB:Engine Type=5;" & _
''                                 "Persist Security Info=False;"
    conn.Open sConn

    'sqlText = How to reference Valid SQL cells
    lRow = 1
    Do
        sqlText = Sheets("SQL").Range("A" & lRow)
        If sqlText = "" Then
            MsgBox "Finished processing " & lRow & " rows of SQL", vbOKOnly, "Finished"
            GoTo Wrap_Up
        End If

        Set rs = New ADODB.Recordset
        rs.Open sqlText, conn, adOpenStatic, adLockBatchOptimistic, adCmdText

        Data.Cells(lRow, 1) = sqlText

       If not rs.EOF then
        For iFldCt = 1 To rs.Fields.Count
            Data.Cells(lRow, 1 + iFldCt) = rs.Fields(iFldCt - 1).Name
        Next

        If rs.RecordCount < Rows.Count Then
            Data.Range("B" & lRow).CopyFromRecordset rs
        Else
            Do While Not rs.EOF
               Row = Row + 1
               For Findex = 0 To rs.Fields.Count - 1
                 If Row >= Rows.Count - 50 Then
                    Exit For
                 End If
                 Data.Cells(Row + 1, Findex + 1) = rs.Fields(Findex).value
               Next Findex
               rs.MoveNext
            Loop
        End If
        Cells.EntireColumn.AutoFit
      End If
        lRow = lRow + 1
    Loop
Wrap_Up:
    rs.Close
    Set rs = Nothing
    conn.Close
    Set conn = Nothing
End Sub

【讨论】:

  • 似乎没有添加任何 strSql = "strSql = """ & strSql & """",查看调试时添加了双引号
  • 可能是 Replace(strSql, vbCrLf, strcLineEnd)?
  • 您是否尝试获取有效的 SQL 字符串并转换为可以执行的“字符串”?或者您是否尝试将 SQL 字符串解析为多行带有续行的 VBA 代码?我取了字符串(忽略 |)|SELECT Table1.*, Table1.FldA FROM Table1 WHERE (((Table1.FldA)="A1"));|并转换为 |strSql = "SELECT Table1.*, Table1.FldA FROM Table1 WHERE (((Table1.FldA)=""A1""));"|
  • 是的 - 我正在尝试获取一个有效的 SQL 字符串并将其转换为可以通过 VBA 执行的字符串..抱歉造成混淆
  • 确保只有 1 行返回“Select Top 1 ...”。要测试1个以上,打开RS后:| RS.MoveLast | RS.MoveFirst | Debug.Print RS.Recordcount |
【解决方案2】:

我正在使用这样的东西:

Function SQLQueryRun(ByVal query As String, ByVal returnData As Boolean) As Variant
Dim Conn As New ADODB.Connection
Dim ADODBCmd As New ADODB.Command
Dim ret As New ADODB.Recordset

    Conn.ConnectionString = "connection_string_here"
    Conn.Open
    ADODBCmd.ActiveConnection = Conn
    ADODBCmd.CommandText = query
    Set ret = ADODBCmd.Execute()
    If returnData Then
        If Not ret.EOF Then SQLQueryRun = ret.GetRows()
    Else
        SQLQueryRun = True
    End If
    Conn.Close
    Set Conn = Nothing
    Set ret = Nothing
End Function

如果第二个参数是False,函数不会返回任何内容。您是否期待查询运行的结果?
我还使用宏从 Windows 剪贴板中包含的 sql 创建 Query/Pivot 表,如果您有兴趣,请告诉我。

【讨论】:

  • 谢谢,但我的主要问题是将我的 SQL Select 转换为 VBA,我已经能够通过 VBA 从我的数据库中运行查询我只是想用正确的 VBA 表示法得到它
  • 将 SQL 转换为 VBA 究竟是什么意思?
  • 如果您有 SQL,则无需转换。查询不是“在 VBA 中运行”。 VBA 只是在其他地方为该 SQL 的执行提供便利。 SQL 就是 SQL。
  • 抱歉,转换可能不是正确的词,但为了在 VBA 上运行查询,它需要以某种方式格式化。如果你去我的链接提供你会看到他需要更改字符串才能在 VBA 上运行
  • 您的查询是否包含在一个 Excel 行中?
【解决方案3】:

您需要创建与数据库的连接并遍历所有单元格并在每个单元格中执行您的代码。

您可以使用ADO来建立连接(需要添加对Microsoft ActiveX Data Objects 6.1 Library的引用)

您需要找出您的connection string,打开一个连接,然后遍历所有单元格并在这些单元格中执行 SQL。

Dim cnn As New ADODB.Connection
Dim connectionString As String
Dim cmd As New ADODB.Command
Dim c As Range, ws As Worksheet
Dim rst as ADODB.Recordset

connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data source=C:\Database3.accdb;Persist Security Info=False;"
cnn.Open connectionString
cmd.ActiveConnection = cnn

For Each c In ws.Range()
    cmd.CommandText = c.Value
    set rst = cmd.Execute 
    'do what you need to with your new recordset before moving on to the next SELECT
Next c

【讨论】:

  • 谢谢,但我的主要问题是将我的 SQL Select 转换为 VBA
  • @JohnJones 我更新包括返回记录集
  • 嘿巴德 - 让我更新我的问题以包含我的代码。
猜你喜欢
  • 2021-12-27
  • 2011-11-28
  • 2014-07-11
  • 2018-11-24
  • 1970-01-01
相关资源
最近更新 更多