【问题标题】:Refer to QueryTable objects by name按名称引用 QueryTable 对象
【发布时间】:2021-08-25 04:09:52
【问题描述】:

我正在使用 VBA 开发一个 MS Excel 2013 工具,其中涉及到 QueryTables 的使用。

一个不便之处在于访问 Excel 工作表中的现有 QueryTables。目前,我能找到访问查询表的唯一方法是整数索引。我想出了以下代码来快速验证概念:

Sub RefreshDataQuery()

Dim querySheet As Worksheet
Dim interface As Worksheet

Set querySheet = Worksheets("QTable")
Set interface = Worksheets("Interface")

Dim sh As Worksheet
Dim QT As QueryTable

Dim startTime As Double
Dim endTime As Double

Set QT = querySheet.ListObjects.item(1).QueryTable

startTime = Timer
QT.Refresh
endTime = Timer - startTime

interface.Cells(1, 1).Value = "Elapsed time to run query"
interface.Cells(1, 2).Value = endTime
interface.Cells(1, 3).Value = "Seconds"

End Sub

这行得通,但我不想这样做。最终产品工具将有多达五个不同的查询表。我想通过名称来引用 QueryTable。

我该如何翻译:

Set QT = querySheet.ListObjects.item(1).QueryTable

大致如下:

Set QT = querySheet.ListObjects.items.QueryTable("My Query Table")

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    在 Excel 2003 和更早版本中,外部数据连接会创建一个父对象是工作表的 QueryTable 对象。您可以通过 QueryTables 集合对象访问 QueryTable 对象。像大多数集合对象一样,您可以将索引号或名称传递给(默认)Item 方法来获取它。

    Sheet1.QueryTables("MyQtName")
    

    当您在新版本中打开 2003 工作表时,它仍然有一个 QueryTable 对象,并且可以以相同的方式访问。即使您转换文件格式,QueryTable 仍然存在。

    在 2007 及更高版本中,只有三种方法可以创建将成为 Worksheet.QueryTables 成员的 QueryTable:

    1. 通过代码
    2. 数据 - 来自文本
    3. 数据 - 来自网络

    这些新版本中的所有其他 UI 外部数据连接都不会生成 QueryTables 成员,而是生成 ListObject。该 ListObject 将只有一个 QueryTable 对象,可以通过 ListObject.QueryTable 属性访问。

    这是坏消息。 ListObject 中其父级没有 Name 属性的 QueryTable。好吧,它就在那里,但是如果您尝试访问它,您将收到运行时错误 1004。我猜 MS 决定了,因为每个 ListObject 只有一个 QueryTable,所以它应该有一个名字是没有意义的。

    如果您尝试将 Worksheet.QueryTables.QueryTable 转换为 ListObject,外部数据连接将消失,新的 ListObject 没有 QueryTable。

    由于您的 QueryTables.Count 返回零,因此您的所有 QueryTables 都在 ListObjects 内并且没有名称。 ListObjects 有名字。你可以使用

    Sheet1.ListObjects("MyListName").QueryTable
    

    这是一个函数,它接受一个名称和一个工作表,并返回一个具有该名称的 QueryTable,或者是具有该名称的 ListObject 的子级。

    Public Function QueryTableByName(ByVal sName As String, ByRef sh As Worksheet) As QueryTable
    
        Dim qt As QueryTable
        Dim lo As ListObject
    
        On Error Resume Next
            Set qt = sh.QueryTables(sName)
        On Error GoTo 0
    
        If qt Is Nothing Then
            On Error Resume Next
                Set lo = sh.ListObjects(sName)
            On Error GoTo 0
    
            If Not lo Is Nothing Then
                On Error Resume Next
                    Set qt = lo.QueryTable
                On Error GoTo 0
            End If
        End If
    
        Set QueryTableByName = qt
    
    End Function
    

    【讨论】:

    • 很棒的总结和功能!
    • 这非常有用且具有描述性。谢谢!
    • @Dick Kusleika 遗憾的是,ListObjects 似乎在 2013 年不再具有 name 属性或 QueryTable 属性。
    • ListObjects 是一个集合对象,其中包含工作表上的所有 ListObject 对象。 ListObject 是一个包含单个实例的对象。集合对象从来没有 Name 或 QueryTable 属性,但 ListObject 仍然有。至少根据 MSDN。
    • @DickKusleika 我没有看到属于工作表的 ListObject 对象。他们可能已经处理掉了。
    【解决方案2】:

    根据this MSDN link for ListObject,没有QueryTables 的任何集合是ListObjects 的属性。正确的代码是:

    Set QT = querySheet.ListObjects.items(1).QueryTable
    

    您可能需要参考适当的ListObject item,例如(只是示例代码):

    Dim LS as ListObject
    Set LS = querySheet.ListObjects("My LO 1")
    Set QT = LS.QueryTable
    

    另一种选择是通过WorkSheet property这样引用QT:

    Set QT = Worksheet("QTable").QueryTables("My Query Table")
    

    【讨论】:

    • 设置 QT = querySheet.ListObjects.items.QueryTable 无法编译。我没有看到 ListObjects 的项目属性。对于您的第二个建议,Set QT = Worksheet("QTable").QueryTables("My Query Table"),这对我不起作用,因为 QTable 是预先存在的。
    • 我将其更改为:Set QT = querySheet.ListObjects.items(1).QueryTable,与您的代码类似。
    • 你是什么意思'工作表是预先存在的?'......这很明显 - 将 QT 的名称更改为您真正拥有的名称。您始终可以通过这种方式检查工作表中 QT 的数量:Debug.Print Worksheets("QTable").QueryTables.Count 和每个 QT 的名称:ly have. You can always check number of QT in sheet in this way: Debug.Print Worksheets("QTable").QueryTables(1).Name` for first一。
    • 很抱歉,如果不清楚。 QueryTable 不是通过 VBA 构建的。它是由各种用户通过数据连接向导构建的。即使我可以通过 ListObjects.item(1).QueryTable 访问 QueryTable,我之前尝试过的您发布的代码的计数也会显示为 0
    • 所以,我猜 ListObject 数据来自外部来源。因此,要使用 QT,您需要找到合适的 ListObject 并使用 ListObject.QueryTable 参考。
    【解决方案3】:

    这行得通:

    Range("ClassifiedAsSupply").ListObject.QueryTable.Refresh BackgroundQuery:=True
    

    感谢钉拍数据:https://www.dingbatdata.com/2017/11/24/referencing-listobjects-with-vba/#comment-719

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-30
      • 2011-04-20
      • 1970-01-01
      • 2014-01-16
      • 2016-06-02
      • 1970-01-01
      相关资源
      最近更新 更多