过滤列中的 VBA 粘贴公式

Posted

技术标签:

【中文标题】过滤列中的 VBA 粘贴公式【英文标题】:VBA paste formulas from filtered column 【发布时间】:2015-08-18 19:31:16 【问题描述】:

Excel(VBA) 中是否可以从 1 个语句中的过滤列中复制/粘贴公式?这有效:

Sheets(1).Range("A2:C" & LastRow).Copy
Sheets(2).Range("A2:C" & Range("D" & Rows.Count).End(xlUp).Row).PasteSpecial xlPasteFormulas

但这会返回混乱的行(可能是因为列被过滤了):

Sheets(2).Range("A2:C" & Range("D" & Rows.Count).End(xlUp).Row).Formula = Sheets(1).Range("A2:C" & LastRow).Formula

如果可以在不使用剪贴板的情况下在 1 条语句中执行此操作,有什么想法吗?

编辑

在 Sheet1 中,我将公式添加到 A、B 和 C 列:

With Sheets(1)
    LastRow = .Range("D" & Rows.Count).End(xlUp).Row
    .Range("A5:A" & LastRow).Value = "=D5/$A$3*100"
    .Range("A:AG").AutoFilter Field:=22, Criteria1:=">=1/1/2014", Operator:=xlAnd, Criteria2:="<=12/31/2014"
    .Range("B5:B" & LastRow).SpecialCells(xlCellTypeVisible).Value = "=D" & .UsedRange.Offset(5, 0).SpecialCells(xlCellTypeVisible).Row & "/$B$3*100"
    .Range("A:AG").AutoFilter Field:=22, Criteria1:=">=1/1/2015"
    .Range("C5:C" & LastRow).SpecialCells(xlCellTypeVisible).Value = "=D" & .UsedRange.Offset(5, 0).SpecialCells(xlCellTypeVisible).Row & "/$C$3*100"
    .ShowAllData
End With

因此A列有公式“=Dn/$A$3*100,其中n是行号。B和C公式除以B3和C3单元格值。然后我过滤Sheet1,复制过滤后的行并将它们粘贴到Sheet2

Sheets(1).Range("A4:AG" & LastRow).AutoFilter Field:=7, Criteria1:=name
Sheets(1).Range("A5:C" & LastRow).Copy
Sheets(2).Range("A5:C" & Range("D" & Rows.Count).End(xlUp).Row).PasteSpecial xlPasteFormulas

【问题讨论】:

您是否尝试过使用.FormulaLocal 而不是.Formula?还有.FormulaHidden.FormulaArray 可能会有所帮助。 我试过了,但没有用,只有在过滤器第一次排除行之前才更正值。无论如何感谢您的建议 也许Enum XlCellType有一些东西可以挖掘,包含:Const xlCellTypeFormulas = -4123 (&amp;HFFFFEFE5) Const xlCellTypeVisible = 12 你能添加一个公式示例的图片吗?过滤了哪个工作表?复制面还是粘贴面?请注意.End 将跳过隐藏单元格,这些单元格在您过滤数据后变得相关。您能否还显示LastRow 的来源?我让你的代表超过 10 点,所以你可以发一张照片。 【参考方案1】:

这可以做到,但将公式带到另一个工作表会出现问题。该公式可以在循环中选取,但需要修改单元格地址以反映原始工作表名称。如果应用Application.ConvertFormula method 并将公式转换为严格的xlAbsolute 样式,则可以检查每个$ 以查看以原始工作表名称开头是否合适。您提供的公式(例如 =Dn/$A$3*100)相当简单,解析时应该不会出现任何问题。

Sub Copy_Filtered_Formulas()
    Dim lr As Long, lc As Long, rVIS As Range
    Dim vr As Long, vc As Long, sFRML As String, p As Long
    Dim ws1 As Worksheet, ws2 As Worksheet

    Set ws1 = Sheets("Sheet1")
    Set ws2 = Sheets("Sheet2")

    With ws2
        If Not IsEmpty(.Cells(5, 1)) Then
            With .Range(.Cells(5, 1), .Cells(Rows.Count, 1).End(xlUp))
                .Resize(.Rows.Count, 3).ClearContents
            End With
        End If
    End With

    With ws1
        If .AutoFilterMode Then .AutoFilterMode = False
        lc = .Range("AG:AG").Column
        lr = .Cells(Rows.Count, 1).End(xlUp).Row
        With .Cells(4, 1).Resize(lr - 3, lc)
            With .Offset(1, 0).Resize(.Rows.Count - 1, 3)
                .Formula = "=$D5/A$3*100"
            End With
            .AutoFilter field:=7, Criteria1:=0
            With .Offset(1, 0).Resize(.Rows.Count - 1, 3)
                If CBool(Application.Subtotal(103, .Cells)) Then
                    For Each rVIS In Intersect(.SpecialCells(xlCellTypeVisible), .SpecialCells(xlCellTypeFormulas))
                        sFRML = Application.ConvertFormula(rVIS.FormulaR1C1, xlR1C1, xlA1, xlAbsolute, rVIS)
                        p = InStr(1, sFRML, Chr(36))
                        Do While CBool(p)
                            If Asc(Mid(sFRML, p + 1, 1)) >= 65 And _
                              Asc(Mid(sFRML, p + 1, 1)) <= 90 And _
                              Asc(Mid(sFRML, p - 1, 1)) <> 33 And _
                              Asc(Mid(sFRML, p - 1, 1)) <> 58 Then
                                sFRML = Left(sFRML, p - 1) & Chr(39) & .Parent.Name & Chr(39) & Chr(33) & Mid(sFRML, p, 999)
                                p = InStr(p + Len(.Parent.Name) + 5, sFRML, Chr(36))
                            Else
                                p = InStr(p + 3, sFRML, Chr(36))
                            End If
                        Loop
                        With ws2
                            .Cells(Rows.Count, rVIS.Column).End(xlUp).Offset(1, 0).Formula = sFRML
                        End With
                    Next rVIS
                End If
            End With
        End With
    End With
End Sub

当然,如果您从未打算将原始工作表的名称与公式一起传输,那么可以丢弃很多代码。

【讨论】:

以上是关于过滤列中的 VBA 粘贴公式的主要内容,如果未能解决你的问题,请参考以下文章

VBA - 复制单元格并粘贴列中的空行

如何根据列中的公式结果运行过滤器?

VBA过滤后选择可见单元格

循环遍历过滤的单元格列表以检查值是不是出现在另一列中,然后复制/粘贴

VBA 列循环

按月过滤的 VBA 宏,仅将当月的数据粘贴到不同的工作表上