任务是自动化OLAP透视表数据过滤。在名为sPivotFieldName的透视字段中有一些项目需要排除。下面的代码工作得很好。
With Worksheets(sWorksheetName).PivotTables(sPivotTableName)
With .CubeFields(sCubeFieldName)
.Orientation = xlRowField
.IncludeNewItemsInFilter = True
End With
.PivotFields(sPivotFieldName).HiddenItemsList = vSomeItemsToExclude
End With
但是当我试图将多维数据集字段“.Orientation”属性的值更改为xlPageField时,问题出现了。每次都会引发运行时错误1004。下面是一个示例:
With Worksheets(sWorksheetName).PivotTables(sPivotTableName)
With .CubeFields(sCubeFieldName)
.Orientation = xlPageField
.IncludeNewItemsInFilter = True
End With
.PivotFields(sPivotFieldName).HiddenItemsList = vSomeItemsToExclude
End With
原因似乎是页面字段中的字段项在被放置在行字段中时是不可见的(例如,可以将其视为行标题)。或者可能还有其他原因。我错过了什么?
3条答案
按热度按时间rjee0c151#
这个功能显然不适用于PageFields。在我看来,一个解决方案是使用.VisibleITemsList方法,但要确保它不包括您想要排除的项。
要做到这一点,你需要将所有未过滤的项目转储到一个变量中,循环变量寻找你想要隐藏的术语,如果你找到了,只需将该元素替换为你不想隐藏的其他元素。(这节省了你创建一个没有该项目的新数组)。
棘手的事情是获取所有未过滤项目的列表:如果数据透视表没有应用某种过滤器,.VisibleItemsList就不会给予你。所以我们需要偷偷地复制数据透视表,将感兴趣的PageField设置为RowField,删除所有其他字段,然后用鼠标悬停完整的项目列表,这样我们就知道在删除应该隐藏的项目之后哪些项目应该是可见的。
这里有一个函数,它可以处理过滤,不管你是处理RowField还是PageField,也不管你是想使用.VisibleItemsList还是. HiddenItemsList来设置过滤器
在你的特殊情况下,你会这样称呼它:FilterOLAP SomePivotField,vSomeItemsToExclude,False
unhi4e5o2#
有人请,显示我的例子,它是如何工作的((
在此调试
yzuktlbb3#
我希望我现在给出答案还不算太晚,只是为了子孙后代。
如果您查看任何OLAP数据透视表上的
PivotTable.MDX
属性,您可以看到Excel实际上在后台使用的MDX查询来填充数据透视表中显示的数据。受此观察的启发,我对自己说:难道不应该更狡猾一点吗?(a)用PivotCache使用的同一个连接字符串创建一个ADODB连接,(b)自己组合一个适当的MDX查询,(c)直接将结果读入VBA中的一个数组,然后我们可以将PivotField.VisibleItemsList
属性赋给它?这种方法的好处包括…
废话不多说(或者可能需要更多的ADO?呵呵),下面是我想到的VBA子例程。
如果您有兴趣在自己的Workbook中使用它,那么只需将其复制到标准模块中,并使用相关参数调用它。
例如:
FilterOLAPPivotField(ActiveCell.PivotField, Items, False)
将过滤活动单元格下的PivotField,以便它包含Items
数组中的所有项目 * 除外 *。我在我的机器上测试时观察到一个奇怪的现象:有时,如果我刚打开一个包含我试图操作的PivotField的工作簿,
CubeField.EnableMultiplePageItems
似乎认为它是只读属性。因为子例程写入此属性,这可能会导致它失败。在UI中单击一次以打开过滤器下拉列表似乎总是使问题消失。不确定这背后的确切原因...也许在我真正与数据透视表交互之前,数据透视缓存没有加载?如果其他人有一些见解,我很有兴趣了解是什么原因导致了这一点。最后一点补充说明:如果您计划在现有的Excel工作簿上对一堆数据透视域进行一些手动处理,那么您还可以考虑在快速访问工具栏上放置一个按钮,该按钮将活动单元格下的数据透视域上的所有筛选器反转,即包括当前筛选的所有内容并筛选当前包含的所有内容。或者,你可能想有一个带有CommandButton的UserForm,它可以做类似的事情。你可以使用上面的子例程来创建这样一个按钮,通过另一个调用它的子程序,像这样: