AutoFilter未按预期工作,当筛选器不存在时,会复制整个表格内容。

huangapple go评论83阅读模式
英文:

AutoFilter not working as intended, copies the whole table content when filter is not existing

问题

以下是翻译好的部分:

我有以下问题涉及我的VBA代码:我想要过滤表格中的特定值(在这种情况下是“FALSCH”),然后将其复制到另一个表格中。这个操作基本上是有效的,除非在特定列中没有带有值“FALSCH”的单元格。

那么我的代码会标记并复制整个表格的内容,这不是我想要的。我尝试了许多方法来解决这个问题,但都没有奏效,我不知道该怎么办了...

也许有人可以帮助我吗?提前感谢!

代码:

        ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6, Criteria1:="FALSCH"
        Range("Tabelle328").Select
        Selection.Style = "40 % - Akzent2"
        Range("Tabelle328[[GuV Ext. CMIS]:[Kontostand]]").Select
        Selection.Copy
        
        Range("O12").Select
        Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
        ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6
英文:

I have the following issue with my VBA code: I want to filter a table for a specific value (in this case "FALSCH") and copy it into another table. This works pretty well, except for the case that there is no cell in the specific column with the value "FALSCH".

Then my code marks and copies the whole content of my table which I don't want. I tried many ways to fix this issue but nothing not working and I don't know anymore...

Maybe someone could help me with this? Thanks in advance!

Code:

    ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6, Criteria1:="FALSCH"
    Range("Tabelle328").Select
    Selection.Style = "40 % - Akzent2"
    Range("Tabelle328[[GuV Ext. CMIS]:[Kontostand]]").Select
    Selection.Copy
    
    Range("O12").Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
    :=False, Transpose:=False
   ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6

答案1

得分: 1

不需要选择任何内容,On Error Resume Next 不应在大多数情况下使用。它会隐藏所有错误,最好检查是否可以完全避免错误。

编辑 2:
在帖子底部保留了原始代码,以便评论能够放入上下文。我不确定 Autofilter 需要一个标题范围 - 我之前可能是这样假设的,但是当第一行不包含筛选文本时,过滤 DataBodyRange 确实会过滤掉它。我使用 COUNTA (3) 与 SUBTOTAL 来计算范围中可见行的数量。

Sub Test()
    
    '明确指定表格的位置。ThisWorkbook 是包含代码的文件,Tabell328 在Sheet1上。
    Dim lo As ListObject
    Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects("Tabelle328")
    
    With lo
        .Range.AutoFilter Field:=6, Criteria1:="FALSCH"
        
        '剩下多少行?
        If Application.WorksheetFunction.Subtotal(3, .ListColumns(1).DataBodyRange) > 0 Then
            
            '设置对可见单元格的引用。
            '从“GuV Ext. CMIS”开始以及接下来的两列。
            Dim RangeToCopy As Range
            Set RangeToCopy = .ListColumns("GuV Ext. CMIS").DataBodyRange.Resize(, 3).SpecialCells(xlCellTypeVisible)
        
            '仅复制并粘贴值到目标。
            RangeToCopy.Copy
            ThisWorkbook.Worksheets("Sheet1").Range("O12").PasteSpecial Paste:=xlPasteValues
            
        Else
            MsgBox "没有可复制的行"
        End If
    End With

End Sub

原始代码 - 请查看有关为什么它不会始终起作用的评论。

Sub Test()
    
    '明确指定表格的位置。ThisWorkbook 是包含代码的文件,Tabell328 在Sheet1上。
    Dim lo As ListObject
    Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects("Tabelle328")
    
    With lo
        '仅筛选数据正文,而不包括表头。
        .DataBodyRange.AutoFilter Field:=6, Criteria1:="FALSCH"
        
        '剩下多少行?只有标题,还是还有其他内容?
        If lo.Range.SpecialCells(xlCellTypeVisible).Rows.Count > 1 Then
            
            '设置对可见单元格的引用。
            '从“GuV Ext. CMIS”开始以及接下来的两列。
            Dim RangeToCopy As Range
            Set RangeToCopy = lo.ListColumns("GuV Ext. CMIS").DataBodyRange.Resize(, 3).SpecialCells(xlCellTypeVisible)
        
            '仅复制并粘贴值到目标。
            RangeToCopy.Copy
            ThisWorkbook.Worksheets("Sheet1").Range("O12").PasteSpecial Paste:=xlPasteValues
            
        Else
            MsgBox "没有可复制的行"
        End If
    End With

End Sub

**编辑:** 如果要包括标题请在 RangeToCopy 中将 `.DataBodyRange.Resize(, 3)` 更改为 `.Range.Resize(,3)`。

[With 语句](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/with-statement)  
[如何在Excel VBA中避免使用Select](https://stackoverflow.com/questions/10714251/how-to-avoid-using-select-in-excel-vba)
英文:

No need to select anything, and On Error Resume Next shouldn't be used in most cases. It hides all errors, best to check if the error can be avoided all together.

Edit 2:
Have left original code at bottom of post to put comments in context. Not sure about the Autofilter needs a header range - I think I've assumed this before, but filtering DataBodyRange did filter out the first row when it didn't contain the filter text. I've used COUNTA (3) with the SUBTOTAL to count the visible rows in the range.

Sub Test()

    'Be explicit where the table is.  ThisWorkbook is the file containing the code, Tabell328 is on Sheet1.
    Dim lo As ListObject
    Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects("Tabelle328")
    
    With lo
        .Range.AutoFilter Field:=6, Criteria1:="FALSCH"
        
        'How many rows are left?
        If Application.WorksheetFunction.Subtotal(3, .ListColumns(1).DataBodyRange) > 0 Then
            
            'Set a reference to the visible cells.
            'Start at "GuV Ext. CMIS" and the next two columns.
            Dim RangeToCopy As Range
            Set RangeToCopy = .ListColumns("GuV Ext. CMIS").DataBodyRange.Resize(, 3).SpecialCells(xlCellTypeVisible)
        
            'Copy and paste just the values to the destination.
            RangeToCopy.Copy
            ThisWorkbook.Worksheets("Sheet1").Range("O12").PasteSpecial Paste:=xlPasteValues
            
        Else
            MsgBox "No rows to copy"
        End If
    End With

End Sub

Original code - see comments as to why it wouldn't always work.

Sub Test()

    'Be explicit where the table is.  ThisWorkbook is the file containing the code, Tabell328 is on Sheet1.
    Dim lo As ListObject
    Set lo = ThisWorkbook.Worksheets("Sheet1").ListObjects("Tabelle328")
    
    With lo
        'Filter just the body of data, not the table headers as well.
        .DataBodyRange.AutoFilter Field:=6, Criteria1:="FALSCH"
        
        'How many rows are left?  Just the headers, or more than that?
        If lo.Range.SpecialCells(xlCellTypeVisible).Rows.Count > 1 Then
            
            'Set a reference to the visible cells.
            'Start at "GuV Ext. CMIS" and the next two columns.
            Dim RangeToCopy As Range
            Set RangeToCopy = lo.ListColumns("GuV Ext. CMIS").DataBodyRange.Resize(, 3).SpecialCells(xlCellTypeVisible)
        
            'Copy and paste just the values to the destination.
            RangeToCopy.Copy
            ThisWorkbook.Worksheets("Sheet1").Range("O12").PasteSpecial Paste:=xlPasteValues
            
        Else
            MsgBox "No rows to copy"
        End If
    End With

End Sub  

Edit: Change .DataBodyRange.Resize(, 3) to .Range.Resize(,3) in RangeToCopy if you want to include headers.

With statement
How to avoid using Select in Excel VBA

答案2

得分: 1

从Excel表格(ListObject)返回经过筛选的数据

  • 假定您知道条件列的标题(Richtig/Falsch)而不是其索引(6)。

VBA

Sub FilterVBA()
    
    ' 定义常量。
    Const SRC_TABLE As String = "Tabelle328"
    Const SRC_FIRST_COLUMN As String = "GuV Ext. CMIS"
    Const SRC_LAST_COLUMN As String = "Kontostand"
    Const SRC_CRITERIA_COLUMN As String = "Richtig/Falsch"
    Const CRITERION As String = "Falsch"
    Const DST_FIRST_CELL As String = "O12"
    
    Dim wb As Workbook: Set wb = ThisWorkbook ' 包含此代码的工作簿
    ' 确保工作簿处于活动状态...
    If Not wb Is ActiveWorkbook Then wb.Activate
    ' ...以便在未知工作表名称时引用表格:
    Dim lo As ListObject: Set lo = Range(SRC_TABLE).ListObject
    
    Dim ws As Worksheet: Set ws = lo.Range.Worksheet
    
    ' 引用要复制的列的数据区域(不包括标题)。
    Dim CopyAddress As String: CopyAddress = SRC_TABLE & "[[" _
        & SRC_FIRST_COLUMN & "]:[" & SRC_LAST_COLUMN & "]]"
    Dim crg As Range: Set crg = ws.Range(CopyAddress)
    
    ' 筛选表格并引用可见范围(不包括标题)。
    Dim vrg As Range
    With lo
        ' 清除筛选器。
        If .ShowAutoFilter Then ' 防止未处于“自动筛选”模式时出错
            If .AutoFilter.FilterMode Then .AutoFilter.ShowAllData
        End If
        ' 筛选。
        .Range.AutoFilter .ListColumns(SRC_CRITERIA_COLUMN).Index, CRITERION
        ' 尝试引用可见范围。
        On Error Resume Next
            Set vrg = .DataBodyRange.SpecialCells(xlCellTypeVisible)
        On Error GoTo 0
        ' 清除筛选器。
        .AutoFilter.ShowAllData
    End With
    
    ' 引用第一个目标行。
    Dim drrg As Range:
    Set drrg = ws.Range(DST_FIRST_CELL).Resize(, crg.Columns.Count)
    ' 清除下方(包括第一行)。
    drrg.Resize(ws.Rows.Count - drrg.Row + 1).Clear
    
    If Not vrg Is Nothing Then ' 引用了可见范围
        
        ' 仅引用可见范围的复制列。
        Set vrg = Intersect(crg, vrg)
        
        Dim arg As Range, arCount As Long
        ' 通过赋值方式仅复制值。
        For Each arg In vrg.Areas
            arCount = arg.Rows.Count
            drrg.Resize(arCount).Value = arg.Value
            Set drrg = drrg.Offset(arCount)
        Next arg
    
    'Else ' 未引用可见范围(无匹配)
    End If
    
End Sub

Microsoft 365公式

在单元格 O12 中:

=FILTER(Tabelle328[[GuV Ext. CMIS]:[Kontostand]],Tabelle328[Richtig/Falsch]="Falsch","")

您可以使用以下方式在VBA中编写公式(不太确定为什么要这样做):

Sub FilterFormula()

    Dim wb As Workbook: Set wb = ThisWorkbook ' 包含此代码的工作簿
    ' 确保工作簿处于活动状态...
    If Not wb Is ActiveWorkbook Then wb.Activate
    ' ...以便在未知工作表名称时引用表格:
    Dim ws As Worksheet: Set ws = Range("Tabelle328").ListObject.Range.Worksheet

    ' 写入公式。
    ws.Range("O12").Formula2 = "=FILTER(Tabelle328[[GuV Ext. CMIS]" _
        & ":[Kontostand]],Tabelle328[Richtig/Falsch]=""Falsch"","""")"

    ' 转换为值(不建议,为什么要这样做?)。
'    With ws.Range("O12").CurrentRegion
'        .Value = .Value
'    End With

End Sub
英文:

Return Filtered Data From an Excel Table (ListObject)

  • It is assumed that you know the title of the criteria column (Richtig/Falsch) instead of its index (6).

VBA

<!-- language: lang-vb -->

Sub FilterVBA()
&#39; Define constants.
Const SRC_TABLE As String = &quot;Tabelle328&quot;
Const SRC_FIRST_COLUMN As String = &quot;GuV Ext. CMIS&quot;
Const SRC_LAST_COLUMN As String = &quot;Kontostand&quot;
Const SRC_CRITERIA_COLUMN As String = &quot;Richtig/Falsch&quot;
Const CRITERION As String = &quot;Falsch&quot;
Const DST_FIRST_CELL As String = &quot;O12&quot;
Dim wb As Workbook: Set wb = ThisWorkbook &#39; workbook containing this code
&#39; Ensure the workbook is active...
If Not wb Is ActiveWorkbook Then wb.Activate
&#39; ... to reference the table when the name of the worksheet is unknown:
Dim lo As ListObject: Set lo = Range(SRC_TABLE).ListObject
Dim ws As Worksheet: Set ws = lo.Range.Worksheet
&#39; Reference the copy columns&#39; data body range (headers excluded).
Dim CopyAddress As String: CopyAddress = SRC_TABLE &amp; &quot;[[&quot; _
&amp; SRC_FIRST_COLUMN &amp; &quot;]:[&quot; &amp; SRC_LAST_COLUMN &amp; &quot;]]&quot;
Dim crg As Range: Set crg = ws.Range(CopyAddress)
&#39; Filter the table and reference the visible range (headers excluded).
Dim vrg As Range
With lo
&#39; Clear filter.
If .ShowAutoFilter Then &#39; prevent error if not in &#39;auto filter mode&#39;
If .AutoFilter.FilterMode Then .AutoFilter.ShowAllData
End If
&#39; Filter.
.Range.AutoFilter .ListColumns(SRC_CRITERIA_COLUMN).Index, CRITERION
&#39; Attempt to reference the visible range.
On Error Resume Next
Set vrg = .DataBodyRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
&#39; Clear filter.
.AutoFilter.ShowAllData
End With
&#39; Reference the first destination row.
Dim drrg As Range:
Set drrg = ws.Range(DST_FIRST_CELL).Resize(, crg.Columns.Count)
&#39; Clear below (incl. first row).
drrg.Resize(ws.Rows.Count - drrg.Row + 1).Clear
If Not vrg Is Nothing Then &#39; the visible range was referenced
&#39; Reference only the copy columns of the visible range.
Set vrg = Intersect(crg, vrg)
Dim arg As Range, arCount As Long
&#39; Copy only values &#39;by assignment&#39;.
For Each arg In vrg.Areas
arCount = arg.Rows.Count
drrg.Resize(arCount).Value = arg.Value
Set drrg = drrg.Offset(arCount)
Next arg
&#39;Else &#39; the visible range was not referenced (no match)
End If
End Sub

AutoFilter未按预期工作,当筛选器不存在时,会复制整个表格内容。

Microsoft 365 Formula

In cell O12:

=FILTER(Tabelle328[[GuV Ext. CMIS]:[Kontostand]],Tabelle328[Richtig/Falsch]=&quot;Falsch&quot;,&quot;&quot;)

You can write the formula using VBA in the following way (not quite sure why you would do it though):

<!-- language: lang-vb -->

Sub FilterFormula()
Dim wb As Workbook: Set wb = ThisWorkbook &#39; workbook containing this code
&#39; Ensure the workbook is active...
If Not wb Is ActiveWorkbook Then wb.Activate
&#39; ... to reference the worksheet when its name is unknown:
Dim ws As Worksheet: Set ws = Range(&quot;Tabelle328&quot;).ListObject.Range.Worksheet
&#39; Write formula.
ws.Range(&quot;O12&quot;).Formula2 = &quot;=FILTER(Tabelle328[[GuV Ext. CMIS]&quot; _
&amp; &quot;:[Kontostand]],Tabelle328[Richtig/Falsch]=&quot;&quot;Falsch&quot;&quot;,&quot;&quot;&quot;&quot;)&quot;
&#39; Convert to values (not recommended i.e. why?).
&#39;    With ws.Range(&quot;O12&quot;).CurrentRegion
&#39;        .Value = .Value
&#39;    End With
End Sub

答案3

得分: 0

尝试在每个部分中声明 "Option Explicit"。不要使用 "Select" 来引用实体,而是直接引用它。在你的情况下,你需要选择具有属性 "xlCellTypeVisible" 的单元格,就像下面的示例一样:

Option Explicit
Sub Unckown()
Dim visRng As Range
ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter field:=6, Criteria1:="FALSCH"
On Error Resume Next
Set visRng = Range("Tabelle328").SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not visRng Is Nothing Then
'visRng.Style = "40 % - Akzent2"
Range("Tabelle328[[GuV Ext. CMIS]:[Kontostand]]").Copy
Range("O12").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter field:=6
End Sub
英文:

Try to declare Option Explicit in every Section. Do not use Select to refer to an entity, but make a direct reference to it. In your case you have to select the cells with the property xlCellTypeVisible, as in the example:

Option Explicit
Sub Unckown()
Dim visRng As Range
ActiveSheet.ListObjects(&quot;Tabelle328&quot;).Range.AutoFilter field:=6, Criteria1:=&quot;FALSCH&quot;
On Error Resume Next
Set visRng = Range(&quot;Tabelle328&quot;).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not visRng Is Nothing Then
&#39;visRng.Style = &quot;40 % - Akzent2&quot;
Range(&quot;Tabelle328[[GuV Ext. CMIS]:[Kontostand]]&quot;).Copy
Range(&quot;O12&quot;).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
ActiveSheet.ListObjects(&quot;Tabelle328&quot;).Range.AutoFilter field:=6
End Sub

答案4

得分: -1

尝试这样做

ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6, Criteria1:="FALSCH"
Dim filteredRange As Range
On Error Resume Next
Set filteredRange = ActiveSheet.ListObjects("Tabelle328").Range.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not filteredRange Is Nothing Then
Range("Tabelle328").Style = "40 % - Akzent2"
Range("Tabelle328[[GuV Ext. CMIS]:[Kontostand]]").Copy
Range("O12").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
ActiveSheet.ListObjects("Tabelle328").Range.AutoFilter Field:=6
英文:

Try this

ActiveSheet.ListObjects(&quot;Tabelle328&quot;).Range.AutoFilter Field:=6, Criteria1:=&quot;FALSCH&quot;
Dim filteredRange As Range
On Error Resume Next
Set filteredRange = ActiveSheet.ListObjects(&quot;Tabelle328&quot;).Range.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not filteredRange Is Nothing Then
Range(&quot;Tabelle328&quot;).Style = &quot;40 % - Akzent2&quot;
Range(&quot;Tabelle328[[GuV Ext. CMIS]:[Kontostand]]&quot;).Copy
Range(&quot;O12&quot;).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
ActiveSheet.ListObjects(&quot;Tabelle328&quot;).Range.AutoFilter Field:=6

huangapple
  • 本文由 发表于 2023年7月3日 21:45:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定