如何使用 VBA 向单元格添加公式

How to add a Formula To Cell using VBA

我正在尝试编写一些 VBA,它将向 3 个单元格添加 header 文本,然后将公式一直填充到最后一行。我写了下面的内容,写 header 没问题,但是当它到达我的第一个 .Formula 时它抛出一个

Application Defined or Object Defined error

需要更改什么才能成功执行此宏? (公式是直接从单元格中的公式中提取的,所以我知道它们至少在 "front-end" 上是有效的公式)

Function Gre()
    Range("E2").Select
    ActiveCell.FormulaR1C1 = "Under"
    Range("F2").Select
    ActiveCell.FormulaR1C1 = "Over"
    Range("G2").Select
    ActiveCell.FormulaR1C1 = "Result"

    With Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row)
        .Formula = "=IF(C2<B2,B2-C2,"")"
    End With
    With Range("F2:F" & Cells(Rows.Count, "C").End(xlUp).Row)
        .Formula = "=IF(C2>B2,C2-B2,0)"
    End With
    With Range("G2:G" & Cells(Rows.Count, "C").End(xlUp).Row)
        .Formula = "=IF(F2>0,'Issue',"")"
    End With
End Function

问题可能是您在使用公式转义引号。

您需要的是:

.Formula = "=IF(C2>B2,B2-C2,"""")"

例如第一个。其他引号也需要加倍。

作为旁注,最好指定 sheet 您正在处理的内容,例如:

 Dim ws as worksheet
 Set ws = Sheets("mySheet")
 ws.Range("E2").FormulaR1C1 = "Under"

等等

如果不这样做,有时 运行 代码会出错。

  1. 正如 OpiesDad 所建议的那样,为了尽量减少歧义,请避免使用 ActiveCell 等。
  2. 与直接分配给单元格相比,使用 Select 也会大大降低性能。
  3. 我很确定您需要通过将引号加倍来转义 Excel 公式中 VBA 中的引号,因此普通的空字符串变为 """"。您在公式中的单引号中也有 Issue,我很确定 Excel 中会出错;那也应该在转义双引号中。
  4. 我很难弄清楚 Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) 实际做了什么,但听起来您想 select E2 到 [=47 最后使用的行=].避免 Rows.Count 或只是泛指 sheet 的行,因为那样会转到第 10^31 行。使用 Worksheet.UsedRange 获取从第一行和第一列有内容到最后一行和最后一列有内容的范围。这也包括空字符串,有时可能有点棘手,但通常比处理数千个额外的行要好。

此外,

  1. 如果你只包含一个语句,你不需要使用With,尽管它不会造成任何问题。

  2. 我不会混合使用 Range.FormulaRange.FormulaR1C1 除非你有理由这样做。

    Function Gre() 
    
        Dim ws as Worksheet
        Set ws = ActiveSheet
    
        Dim used as Range
        Set used = ws.UsedRange
    
        Dim lastRow as Integer
        lastRow = used.Row + used.Rows.Count - 1
    
        ws.Range("E2").Formula = "Under"
        ws.Range("F2").Formula = "Over"
        ws.Range("G2").Formula = "Result"
    
        ws.Range("E2:E" & lastRow).Formula = "IF(C2<B2, C2-B2, """")"
        ws.Range("F2:F" & lastRow).Formula = "IF(C2<B2, C2-B2, 0)"
        ws.Range("G2:G" & lastRow).Formula = "IF(F2>0, ""Issue"", """")"
    
    End Function
    

除了使用双引号外,您可能还需要在前两个公式中使用 0,否则它们的计算结果可能为空字符串。这可能会给最后一个公式带来意想不到的结果,即错误地 return "Issue".

如果您的数据和 3 个新列之间没有空白列,您可以使用 CurrentRegion 来确定行数:

Range("E2:E" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2'<'B2,B2-C2,0)"

Range("F2:F" & Cells.CurrentRegion.Rows.Count).Formula = "=if(C2>B2,C2-B2,0)"

Range("G2:G" & Cells.CurrentRegion.Rows.Count).Formula = if(F2>0,""Issue"","""")"
  1. 第一个问题是select单元格。这需要宏select单元格,然后确定单元格地址。如果您实际上需要 select 一个单元格,请使用 Application.ScreenUpdating = False。这样宏就不必显示单元格的光标 selection 了。删除 select 并将范围合并到公式分配代码行中,如下所示将获得一些 speed/efficiency.

    Range("E2").FormulaR1C1 = "Under"

  2. Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row) 是 selecting 空白列(第 1048576 行)中最后一个单元格的代码版本,然后使用 ctrl 的击键和向上键来确定lowest/last 使用过的单元格。由于该列为空白,因此每次都会使您的行计数为 1。由于您正在寻找最后一行。从顶部倒数可能会更快。我最喜欢的方法是循环。在循环中增加一个变量,同时寻找最后一行。然后,可以使用变量代替自下而上的策略。

    t = 0
    Do Until Range("C2").Offset(t, 0).Value = ""
    t = t + 1
    Loop
    
    With Range("E2:E" & t)
    .Formula = "=IF(C2<B2,B2-C2,"""")"
    End With`
    
  3. 就像TSQL一样,引号需要自己的引号。

    .Formula = "=IF(C2<B2,B2-C2,"""")"
    
  4. Range Fillup VBA 函数可以在这种情况下使用,用一个通用公式从底部填充所有单元格,占 Excel 公式参考相关性。下面的代码从我们从循环计数器得到的范围开始。接下来,我们设置一个变量等于 Excel 中的总行数减去对应于计数器行的行数。然后,我们根据需要的行调整原始区域的大小,并使用 FillDown 函数向下复制第一个公式。
  5. 这是生成的代码。这将填充从 Excel 中最后一行开始的范围。

     Sub Gre()
     Range("E2").FormulaR1C1 = "Under"
     Range("F2").FormulaR1C1 = "Over"
     Range("G2").FormulaR1C1 = "Result"
    
     Do While Range("e2").Offset(t, 0).Value <> ""
     t = t + 1
     Loop
     Range("E2").Offset(t, 0).Formula = "=IF(C2<B2,B2-C2,"""")"
     r1 = Range("e2").EntireColumn.Rows.Count
     r2 = Range("E2").Offset(t, 0).Row
     Range("E2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
     Range("F2").Offset(t, 0).Formula = "=IF(C2>B2,C2-B2,0)"
     Range("F2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
     Range("G2").Offset(t, 0).Formula = "=IF(F2>0,""Issue"","""")"
     Range("G2").Offset(t, 0).Resize(r1 - r2, 1).FillDown
     End Sub
    

请尝试以下示例希望它能帮助您在 VBA

中编写公式
   Sub NewEntry()
    Dim last_row As Integer
    Dim sht1 As Worksheet
    Dim StockName As String

Set sht1 = Worksheets("FNO MW")
last_row = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'MsgBox last_row
StockName = sht1.Cells(last_row, 1).Value
sht1.Cells(last_row, 1).Formula = "=RTD(""pi.rtdserver"", ,"" " & StockName & " "", ""TradingSymbol"")"

结束子