如何使用 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"
等等
如果不这样做,有时 运行 代码会出错。
- 正如 OpiesDad 所建议的那样,为了尽量减少歧义,请避免使用
ActiveCell
等。
- 与直接分配给单元格相比,使用
Select
也会大大降低性能。
- 我很确定您需要通过将引号加倍来转义 Excel 公式中 VBA 中的引号,因此普通的空字符串变为
""""
。您在公式中的单引号中也有 Issue
,我很确定 Excel 中会出错;那也应该在转义双引号中。
- 我很难弄清楚
Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row)
实际做了什么,但听起来您想 select E2
到 [=47 最后使用的行=].避免 Rows.Count
或只是泛指 sheet 的行,因为那样会转到第 10^31 行。使用 Worksheet.UsedRange
获取从第一行和第一列有内容到最后一行和最后一列有内容的范围。这也包括空字符串,有时可能有点棘手,但通常比处理数千个额外的行要好。
此外,
如果你只包含一个语句,你不需要使用With
,尽管它不会造成任何问题。
我不会混合使用 Range.Formula
和 Range.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"","""")"
第一个问题是select单元格。这需要宏select单元格,然后确定单元格地址。如果您实际上需要 select 一个单元格,请使用 Application.ScreenUpdating = False
。这样宏就不必显示单元格的光标 selection 了。删除 select 并将范围合并到公式分配代码行中,如下所示将获得一些 speed/efficiency.
Range("E2").FormulaR1C1 = "Under"
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`
就像TSQL一样,引号需要自己的引号。
.Formula = "=IF(C2<B2,B2-C2,"""")"
- Range Fillup VBA 函数可以在这种情况下使用,用一个通用公式从底部填充所有单元格,占 Excel 公式参考相关性。下面的代码从我们从循环计数器得到的范围开始。接下来,我们设置一个变量等于 Excel 中的总行数减去对应于计数器行的行数。然后,我们根据需要的行调整原始区域的大小,并使用 FillDown 函数向下复制第一个公式。
这是生成的代码。这将填充从 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"")"
结束子
我正在尝试编写一些 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"
等等
如果不这样做,有时 运行 代码会出错。
- 正如 OpiesDad 所建议的那样,为了尽量减少歧义,请避免使用
ActiveCell
等。 - 与直接分配给单元格相比,使用
Select
也会大大降低性能。 - 我很确定您需要通过将引号加倍来转义 Excel 公式中 VBA 中的引号,因此普通的空字符串变为
""""
。您在公式中的单引号中也有Issue
,我很确定 Excel 中会出错;那也应该在转义双引号中。 - 我很难弄清楚
Range("E2:E" & Cells(Rows.Count, "C").End(xlUp).Row)
实际做了什么,但听起来您想 selectE2
到 [=47 最后使用的行=].避免Rows.Count
或只是泛指 sheet 的行,因为那样会转到第 10^31 行。使用Worksheet.UsedRange
获取从第一行和第一列有内容到最后一行和最后一列有内容的范围。这也包括空字符串,有时可能有点棘手,但通常比处理数千个额外的行要好。
此外,
如果你只包含一个语句,你不需要使用
With
,尽管它不会造成任何问题。我不会混合使用
Range.Formula
和Range.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"","""")"
第一个问题是select单元格。这需要宏select单元格,然后确定单元格地址。如果您实际上需要 select 一个单元格,请使用
Application.ScreenUpdating = False
。这样宏就不必显示单元格的光标 selection 了。删除 select 并将范围合并到公式分配代码行中,如下所示将获得一些 speed/efficiency.Range("E2").FormulaR1C1 = "Under"
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`
就像TSQL一样,引号需要自己的引号。
.Formula = "=IF(C2<B2,B2-C2,"""")"
- Range Fillup VBA 函数可以在这种情况下使用,用一个通用公式从底部填充所有单元格,占 Excel 公式参考相关性。下面的代码从我们从循环计数器得到的范围开始。接下来,我们设置一个变量等于 Excel 中的总行数减去对应于计数器行的行数。然后,我们根据需要的行调整原始区域的大小,并使用 FillDown 函数向下复制第一个公式。
这是生成的代码。这将填充从 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"")"
结束子