用 VBA 批量填公式、把明细读进数组计算、找到最后一行再追加数据、按条件筛选后复制。Range 和 Cells 是 Excel VBA 里最常用的对象,写错引用范围或依赖 ActiveSheet,宏就会在别人的电脑上操作错表。
Range("A1").Value = 100
Cells(1, 1).Value = 100 ' 第 1 行第 1 列,等价于 A1
Range("A1:C10").Value = 0
Range(Cells(1, 1), Cells(10, 3)).Value = 0
| 写法 | 含义 |
|---|---|
Range("A1") |
单个单元格 |
Range("A1:C10") |
连续区域 |
Range("A1,A3,C1:C5") |
多个不连续区域 |
Cells(row, col) |
按行列号取单元格 |
Rows(1) / Columns("A") |
整行/整列 |
Range("A1").Offset(1, 0) |
向下偏移一行 |
Range("A1").Resize(5, 2) |
从 A1 扩展为 5 行 2 列 |
Range("A1").EntireRow |
A1 所在的整行 |
Range("A1").EntireColumn |
A1 所在的整列 |
Cells(1, 1) 的行列号从 1 开始。Cells 不写工作表前缀时指当前活动工作表,正式代码里应写成 ws.Cells(...)。
Dim ws As Worksheet
Dim lastRow As Long
Dim lastCol As Long
Set ws = ThisWorkbook.Worksheets("数据")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
End(xlUp) 等价于在 A 列按 Ctrl+↑,从工作表最底部往上找第一个非空单元格。注意:
End(xlUp) 返回第 1 行,不是 0;UsedRange 可能因为曾经设置过格式而扩展到很远的空行,不建议用它判断最后一行。更稳的写法是先判断 A 列是否有数据:
If Application.WorksheetFunction.CountA(ws.Columns("A")) = 0 Then
lastRow = 0
Else
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
End If
ws.Range("A1").Value = "张三"
ws.Range("B1").Value = Date
ws.Range("C1").Formula = "=A1&B1"
ws.Range("D1").NumberFormat = "yyyy-mm-dd"
ws.Range("A1").Font.Bold = True
ws.Range("A1").Interior.Color = RGB(220, 230, 241)
| 属性 | 用途 | 注意 |
|---|---|---|
.Value |
值 | 日期、货币保留类型 |
.Value2 |
值 | 日期/货币按 Double 处理,速度快 |
.Text |
显示文本 | 列宽不够时可能是 ### |
.Formula |
A1 样式公式 | 写入公式用这个 |
.FormulaR1C1 |
R1C1 样式公式 | 相对引用更直观 |
.NumberFormat |
数字格式 | 只影响显示 |
逐格读写很慢。数据量大时先读到数组,计算完再一次性写回:
Sub CalcAmount()
Dim ws As Worksheet
Dim lastRow As Long
Dim data As Variant
Dim result As Variant
Dim i As Long
Set ws = ThisWorkbook.Worksheets("数据")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
data = ws.Range("A2:B" & lastRow).Value
ReDim result(1 To UBound(data, 1), 1 To 1)
For i = 1 To UBound(data, 1)
result(i, 1) = data(i, 1) * data(i, 2)
Next i
ws.Range("C2:C" & lastRow).Value = result
End Sub
从区域读出的数组默认是 1 基、二维的,即 data(1, 1) 对应区域左上角。
Dim found As Range
Set found = ws.Range("A:A").Find( _
What:="A001", _
LookIn:=xlValues, _
LookAt:=xlWhole)
If Not found Is Nothing Then
MsgBox "找到:" & found.Address
End If
Find 找不到时返回 Nothing,必须先判断再使用。LookAt:=xlWhole 是整格匹配,xlPart 是包含匹配。
With ws.Range("A1:D" & lastRow)
.AutoFilter Field:=1, Criteria1:="华东"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).Copy _
Destination:=ThisWorkbook.Worksheets("结果").Range("A1")
.AutoFilter
End With
Field:=1 是区域内的第一列。复制筛选结果前确认目标表有足够空间;筛选后记得关闭筛选。
Range("A1") 和 Cells(1, 1) 默认操作活动工作表;用户切换工作表后就操作错地方。统一写 ws.Range(...)。UsedRange 被格式撑大:曾经设置过格式的空行也会算进 UsedRange;用 End(xlUp) 或 CurrentRegion 判断实际数据。End(xlUp) 返回 1:A 列没有数据时最后一行是 1,不是 0;先判断 CountA。.Text 截断:列宽不够时 .Text 返回 ###,应使用 .Value。MergeArea 判断,或先取消合并。AutoFilter 批量处理。Find 的查找范围:只查一列还是整表要明确;LookIn、LookAt 不写会使用上次查找的设置。合上页面,先回答,再展开对照。
End(xlUp).Row 返回什么?CountA 判断是否有数据。
小程序版
微信扫码,随时查命令