自动筛选与ShowAllData

时间:2019-11-21 18:28:43

标签: excel vba autofilter named-ranges

背景:

自最近以来,我开始了解通过使用AutoFilter创建的秘密命名范围。通常(如果不是总是这样)将其称为“ _FilterDatabase”。

本来我想过玩一点,但后来卡在了它所指的Range对象上。让我用以下示例进行解释:


测试数据:

| Header1 | Header2 |
|---------|---------|
| 50      |         |
| 10      |         |
| 30      |         |
| 40      |         |
| 20      |         |

测试代码:

Sub Test()

With Sheet1
    .Range("A1:B1").AutoFilter 1, ">40"
    Dim rng As Range: Set rng = .Range("_FilterDatabase")
    If rng.SpecialCells(12).Count > 2 Then
        rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
    End If
    .Range("A1:B1").AutoFilter
End With

End Sub

没有结果


问题:

如果我在上面运行宏,将不会有结果。


问题:

使用.ShowAllData方法而不是.AutoFilter并运行两次代码可以解决此问题:

Sub Test()

With Sheet1
    .Range("A1:B1").AutoFilter 1, ">30"
    Dim rng As Range: Set rng = .Range("_FilterDatabase")
    If rng.SpecialCells(12).Count > 2 Then
        rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
    End If
    .ShowAllData
End With

End Sub

但是,.AutoFilter清除了过滤器并将其从我们的范围中删除。在这两种情况下,秘密的命名范围都将保留在名称管理器下的Formulas标签中。

有人知道为什么ShowAllData会在第二轮运行中影响返回的命名范围吗?

2 个答案:

答案 0 :(得分:2)

我已经找到了我自己的问题的答案(事后看来,这似乎不符合我的发现,因此我对其进行了编辑)。

根据我的问题,AutoFilter将立即在水下创建一个加密的命名范围,通常(如果不是始终如此)称为"_FilterDatabase"。我注意到的是以下内容:

.Range("A1:B1").AutoFilter 1, ">40"  '-> Named range will refer to A1:B1

但是:

.Range("A1:B1").AutoFilter '-> Named range will refer to A1:B1
.Range("A1:B1").AutoFilter 1, ">40" '-> Named range will refer to A1:B6

这可以解释为什么我的代码末尾的AutoFilter使得第二次也不能正常工作。但是,由于ShowAllData不会删除实际的过滤器(仅是标准),因此它将在第二次运行中识别出范围A1:B6。因此,我需要做的是首先设置.AutoFilter,以使命名范围选取正确的范围。现在,以下内容可以正常工作:

Sub Test()

With Sheet1
    .Range("A1:B1").AutoFilter
    .Range("A1:B1").AutoFilter 1, ">40"
    Dim rng As Range: Set rng = .Range("_FilterDatabase")
    If rng.SpecialCells(12).Count > rng.Rows(1).Cells.Count Then
        rng.Columns(2).Offset(1).Resize(rng.Rows.Count - 1, 1).Value = "Check"
    End If
    .Range("A1:B1").AutoFilter
End With

End Sub

在逻辑上行不通的是什么呢?

.Range("A1:B1").AutoFilter '-> Named range will refer to A1:B1
Set rng = Set rng = .Range("_FilterDatabase")
rng.AutoFilter 1, ">40" '-> rng still refers to A1:B1

恢复:

AutoFilter立即在AutoFilter方法上创建一个秘密的命名范围。您不能直接使用条件初始化过滤器。这样做会混淆命名范围,并且现在只会引用第一行。必须按顺序使用它们!

有趣的部分是,这现在将不需要事先知道最后一个使用的行来创建范围对象的方法(但是,由于数据中的空白将使命名范围无效,因此可能仍然更喜欢该方法)。

答案 1 :(得分:1)

此过滤器无需使用AutoFilter.Range即可正确过滤:

Sub test2()
Dim var As Range
Dim i As Long
With Sheets("Sheet1").Range("A1:C1")
    .Range("B2:B6").Clear
    .AutoFilter
    .AutoFilter 1, ">50"
        Set var = Sheet1.AutoFilter.Range
        Set var = Intersect(var.SpecialCells(12), var.Offset(1, 0))
        If Not (var Is Nothing) Then
            For i = 1 To var.Areas.Count
                var.Areas(i).Offset(0, 1).Resize(var.Areas(i).Rows.Count, 1).Value = "Check"
            Next i
        End If
    .AutoFilter
End With
End Sub