VBA查询从excel表和SQL数据库中提取数据

时间:2017-08-16 18:08:19

标签: sql sql-server vba excel-vba excel

我已经做了很长一段时间了,我似乎无法弄明白。我正在尝试在excel中创建一个查询,该查询结合了excel表和数据库中的信息。我可以分别做他们每个人没问题。

以下是excel查询的VBA代码:

    Sub ExcelQuery()
'
    Range("Table_Query_from_Excel_Files5[[#Headers],[Customer:]]").Select
    With Selection.ListObject.QueryTable
        .Connection = Array(Array("ODBC;DSN=Excel Files;DBQ=Z:\OEM Office\Trevor Weinrich\Projects\BOM Template 2.0\BOM template 2017-08-16 1.xlsm;DefaultDir=Z:\OEM Office\Trevor Weinrich\Projects\BOM Template 2.0;DriverId=1046;MaxBufferSize=2048;PageTimeout=5;"))
        .CommandText = Array( _
        "SELECT `BOM$`.`Customer:`" & Chr(13) & "" & Chr(10) & "FROM `BOM$` `BOM$`" & Chr(13) & "" & Chr(10) & "WHERE (`BOM$`.`Customer:` Is Not Null)" _
        )
        .Refresh BackgroundQuery:=False
    End With
'
End Sub

以下是数据库查询的VBA代码:

Sub DatabaseQuery()
'
    With Selection.ListObject.QueryTable
        .Connection = _
        "ODBC;DSN=OEM;Description=OEM;UID=trevor.weinrich;Trusted_Connection=Yes;APP=Microsoft Office 2016;WSID=DFP-OEM-0913-A;DATABASE=OEM"
        .CommandText = Array( _
        "SELECT DISTINCT p21_view_item_uom.item_id, p21_view_item_uom.unit_of_measure, p21_view_item_uom.purchasing_unit" & Chr(13) & "" & Chr(10) & "FROM OEM.dbo.p21_view_item_uom p21_view_item_uom" & Chr(13) & "" & Chr(10) & "WHERE (p21_view_item_uom.delete_flag=" _
        , "'N')" & Chr(13) & "" & Chr(10) & "ORDER BY p21_view_item_uom.item_id")
        .Refresh BackgroundQuery:=False
    End With
'
End Sub

我想加入这些,因为数据库查询中有大约140,000个订单项,我只关心数据库中“item_id”字段与“Customer:”字段匹配的实例。 我只是无法弄清楚如何加入他们两个。我非常感谢你的帮助。

这是代码,我只是试图引入一个变量,它给出了165个字符后的错误:

Sub Update_Item_Tables()
'
' UOM_Update Macro
'
Dim Items As String
Items = Sheets("UOM").Range("K1").Value

    Sheets("UOM").Visible = True
    Sheets("UOM").Select
    Range("Table_Query_from_OEM[[#Headers],[item_id]]").Select
    With Selection.ListObject.QueryTable
        .Connection = _
        "ODBC;DSN=OEM;Description=OEM;UID=trevor.weinrich;Trusted_Connection=Yes;APP=Microsoft Office 2016;WSID=DFP-OEM-0913-A;DATABASE=OEM"
        .CommandText = Array( _
        "SELECT DISTINCT p21_view_item_uom.item_id, p21_view_item_uom.unit_of_measure, p21_view_item_uom.purchasing_unit" & Chr(13) & "" & Chr(10) & _
        "FROM OEM.dbo.p21_view_item_uom p21_view_item_uom" & Chr(13) & "" & Chr(10) & _
        "WHERE (p21_view_item_uom.item_id In (" _
        , _
        "" & Items & ")) AND (p21_view_item_uom.delete_flag='N')" & Chr(13) & "" & Chr(10) & _
        "ORDER BY p21_view_item_uom.purchasing_unit DESC" _
        )
        .Refresh BackgroundQuery:=False
    End With

End Sub

2 个答案:

答案 0 :(得分:1)

Yikes ......其中一些代码是......让我们称之为独一无二。但我不会提问,我们暂时处理您要问的问题。

目标是检查长项目字符串,这样您只需要一个Sql命令来获取数据。但是字符串必须是少于165个字符的块。

正如我之前提到的,这是一种草率的方式,但如果他们为了开发目的而将您从SQL数据库中锁定,这种方法将起作用:

您可以将Item字符串拆分为多个字符串,每个字符串少于165个字符。然后,您可以在SQL中使用OR语句,将IN函数用于包含数据的每个Item字符串。

首先,在您的VBA中,您需要:

'Delcare your Variables

Dim SQLText As String
Dim Items2 As String
Dim Items3 As String
Dim boolItemFlag2 As Boolean
Dim boolItemFlag3 As Boolean
Dim i As Integer

' Initialize Variables

boolItemFlag2 = False
boolItemFlag3 = False

然后,您可以进行处理以构建“项目”字符串。我假设它的逗号分隔如下:

Items = "'123456','234567'"

构建完成后,您可以:

' Get your Items list and check for length over 164

If Not IsNull(Len(Items)) Then
   If Len(Items) > 164 Then
      boolItemFlag2 = True
      i = 0

      ' Find last comma delimiter before the cut off of 164

      While (Mid(Items, 164 - i, 1) <> ",")
         i = i + 1
      Wend

      ' Set Items2 to everything after the last comma (before pos 164).  Then Left Trim away possible spaces.

      Items2 = LTrim(Mid(Items, 164 - i + 1, Len(Items) - 164 + i))

      ' Reset Items to everything up to that comma we found but not including it.

      Items = Left(Items, 164 - i - 1)

      ' Your Item list is now split into 2 different string variables

   End If
End If

If Not IsNull(Len(Items2)) Then
   If Len(Items2) > 164 Then
      boolItemFlag3 = True
      ' Use the same logic above to split Items2 into the Items3 variable.
      ' You may need to duplicate again for Items4 etc if your Item List is huge.
      ' If you'd need beyond Items5, I'd probably go back to the two query approach.
      ' But it's your choice.
   End If
End If

然后,在将项目列表拆分为足够小的变量后,可以构建一个唯一的SQL字符串(称为SQLText)并插入OR语句以包含具有数据的项字符串:

' Build your SQL String Here (after you have determined how many item strings you have)

SQLText = "SELECT DISTINCT p21_view_item_uom.item_id, p21_view_item_uom.unit_of_measure, p21_view_item_uom.purchasing_unit" & Chr(13) & "" & Chr(10) & _
     "FROM OEM.dbo.p21_view_item_uom p21_view_item_uom" & Chr(13) & "" & Chr(10) & _
     "WHERE (p21_view_item_uom.item_id In (" _
     & _                  ' <-- I changed your comma into an & because I have no clue...
     "" & Items & ")"

If boolItemFlag2 Then   ' Add this OR statement if Items2 has data
     SQLText = SQLText & " OR p21_view_item_uom.item_id In (" & Items2 & ")"
End If

If boolItemFlag3 Then   ' Add this OR statement if Items3 has data
     SQLText = SQLText & " OR p21_view_item_uom.item_id In (" & Items3 & ")"
End If

' Add more OR statements if you have Item lists beyond 3.

' Now tack on your remaining SQL code:

SQLText = SQLText & ") AND (p21_view_item_uom.delete_flag='N')" & Chr(13) & "" & Chr(10) & _
     "ORDER BY p21_view_item_uom.purchasing_unit DESC"

现在,String SQLText将包含您要发送到服务器的完整SQL代码。如果要验证字符串是否正确,可以执行此消息框:

MsgBox SQLText

您需要再做一次修改。当您调用数据库时,需要将变量SQLText放入commandtext数组(代替旧代码):

' Now you can put your SQLText variable into your ODBC call:

With Selection.ListObject.QueryTable
    .Connection = _
"ODBC;DSN=OEM;Description=OEM;UID=trevor.weinrich;Trusted_Connection=Yes;APP=Microsoft Office 2016;WSID=DFP-OEM-0913-A;DATABASE=OEM"
    .CommandText = Array(SQLText)
    .Refresh BackgroundQuery:=False
End With

希望有所帮助:)

答案 1 :(得分:0)

运行Excel查询。

循环遍历结果集并构建OR条件列表,例如item_id ='ABC'或item_id ='PQR'等。

不使用IN条件,而是在单个大字符串中使用(巨大的)OR条件列表。

将此OR条件列表与查询的其余部分连接为数据库查询的Criterion。

虽然IN短语的长度可能有限制,但完整SQL语句的长度可能为higher

当然,如果没有。将要出现在您的查询中的客户太大,这将有意想不到的问题,具体取决于它的大小。