=INDIRECT(E2) 读取的单元格,其地址以文本形式写在 E2 中。如果 E2 中是 C4,公式就返回 C4 中的值。地址也可以由几部分拼成:=INDIRECT("C"&E3) 读取 C 列中行号为 E3 的单元格。
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Product | Category | Price | Address | Value | |
| 2 | Apple | Fruit | $1.20 | C4 | $0.80 | |
| 3 | Pear | Fruit | $1.50 | 6 | $1.10 | |
| 4 | Carrot | Vegetable | $0.80 | |||
| 5 | Bread | Bakery | $2.40 | |||
| 6 | Milk | Dairy | $1.10 |
F2 读取 C4,也就是 Carrot 的价格 1.10。把 E3 改成 2,就会得到 Apple 的价格。
INDIRECT 语法
=INDIRECT(ref_text, [a1])
ref_text:表示一个引用的文本,例如"C4"、"B2:B6"、"Prices!A2"、"'Price list'!A2:B9"。a1:TRUE或省略时按 A1 样式读取地址。FALSE按 R1C1 样式读取,"R4C3"表示第 4 行第 3 列,适合行和列都是数字的情况。
如果文本不是有效的地址,结果就是 #REF!。INDIRECT 返回的是真正的引用,所以它可以用在 SUM、COUNTIF、VLOOKUP 以及任何接受区域的函数中。
用数字构造区域
地址可以是一整个区域。把一个数字拼进地址,就能得到大小由某个单元格决定的区域。
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Month | Sales | Rows | Total | ||
| 2 | Jan | 4,200 | 3 | 12,900 | ||
| 3 | Feb | 3,900 | ||||
| 4 | Mar | 4,800 | ||||
| 5 | Apr | 5,100 | ||||
| 6 | May | 4,600 | ||||
| 7 | Jun | 5,300 |
E2 中为 3 时,文本变成 B2:B4,F2 把 Jan 到 Mar 相加:12,900。把 E2 设为 6 就得到上半年的合计 27,900。之所以写 1+E2,是因为数据从第 2 行开始。同样的合计也可以不用 INDIRECT 写成 =SUM(B2:INDEX(B2:B7,E2)),它不是易失性的;OFFSET 页面对几种写法做了比较。
引用名称写在单元格中的工作表
工作表名称也可以来自单元格。这样一个汇总公式就变成了跨工作表的查找:每一行读取 A 列中所写名称的那张工作表。名称两边的单引号让带空格的名称也能正常工作。
| A | B | |
|---|---|---|
| 1 | Month | Total |
| 2 | Jan | 12,500 |
| 3 | Feb | 12,200 |
| 4 | Mar | 13,700 |
B2 拼出文本 'Jan'!B2:B4 并求和:12,500。B3 和 B4 是向下填充的同一个公式,所以它们读取 Feb(12,200)和 Mar(13,700)。打开 Feb 标签页改一个数字,汇总会随之更新。在 A2 中把 Jan 改成 Feb,B2 就变成 Feb 的合计。引号里的 B2:B4 是文本,向下填充时不会变化,变化的只有对 A2 的引用。
二级联动下拉列表
第二个下拉列表的选项取决于第一个,这是 INDIRECT 的经典用法。在 Excel 中通常这样设置:
- 把每个类别的选项放在一列中,并用类别名为每个区域命名:选中这些列及其标题,使用“公式 > 根据所选内容创建 > 首行”。这样就创建了名称
Fruit、Vegetable和Dairy。 - 为 A2 设置类别列表:“数据 > 数据验证”,“允许”选“序列”,“来源”填
Fruit,Vegetable,Dairy。 - 为 B2 设置一个来源为
=INDIRECT(A2)的列表。A2 中是 Fruit 时,列表读取名为 Fruit 的区域。
下面的表格用每个类别一张工作表代替命名区域,实现同样的效果。D2 用 INDIRECT 把 A2 中所写工作表的选项溢出显示出来,B2 的列表读取 D2:D4。
| A | B | C | D | |
|---|---|---|---|---|
| 1 | Category | Item | Items for the category | |
| 2 | Fruit | Apple | Apple | |
| 3 | Pear | |||
| 4 | Plum |
在 A2 中选择 Dairy:D2:D4 会换成 Milk、Butter、Cheese,B2 中的选项也一样。B2 会保留原来的值,直到你选择新的值;Excel 也是这样,所以表单常常在选项旁边加一个检查,例如 =COUNTIF(D2:D4,B2)>0。在 Excel 365 中可以不用命名区域,而让第二个列表指向一个溢出公式,例如在辅助单元格中写 =INDIRECT("'"&A2&"'!A2:A4"),再用 =D2# 作为“来源”。其余设置见 下拉列表 页面。
INDIRECT 是易失性函数,而且不理会插入的行
INDIRECT 读取的是文本而不是引用,由此带来两个副作用:
- 每次有改动都会重新计算。 Excel 无法知道一段文本会指向哪些单元格,所以工作簿中任何地方被编辑后,它都会重新计算每一个 INDIRECT。几十个没有影响,几万个会让每次按键都变慢。带行号的 INDEX(
=INDEX(C:C,E3))与=INDIRECT("C"&E3)结果相同,而且只在其输入变化时才重新计算。 - 地址不会移动。 在第 4 行上方插入一行,
=C4会变成=C5,但=INDIRECT("C4")仍然读取 C4,而它现在已经是另一行了。有时这正是想要的效果:无论工作表怎么变,引用都固定在某个单元格上。但更多时候,这是一个等着有人插入行时才会暴露的 bug。
INDIRECT 引用另一个工作簿时,只有在那个工作簿打开时才有效;关闭后会返回 #REF!。
练习:根据行号取价格
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Product | Category | Price | Row | Price | |
| 2 | Apple | Fruit | $1.20 | 5 | ||
| 3 | Pear | Fruit | $1.50 | |||
| 4 | Carrot | Vegetable | $0.80 | |||
| 5 | Bread | Bakery | $2.40 | |||
| 6 | Milk | Dairy | $1.10 |
轮到你了: 在 F2 中用 INDIRECT 返回 C 列中行号为 E2 所写数字的价格。
常见问题
Excel 中的 INDIRECT 函数有什么用?
它把文本变成引用。=INDIRECT("C4") 返回 C4 的值,=INDIRECT(E2) 返回 E2 中所写地址对应单元格的值。地址可以用 & 拼接,所以 =INDIRECT("C"&E2) 读取 C 列中行号为 E2 的那个单元格。
工作表名称写在单元格里,怎样引用这张工作表?
拼接地址时把工作表名称放在单引号里:=INDIRECT("'"&A2&"'!B2")。有了单引号,名称中带空格也能正常工作。=SUM(INDIRECT("'"&A2&"'!B2:B4")) 会对那张工作表上的一个区域求和。
INDIRECT 为什么返回 #REF!?
文本不是有效的地址,或者它指向一张不存在的工作表,或者指向一个已关闭的工作簿。把同样的表达式单独放在一个单元格里(不加 INDIRECT),就能看到公式拼出的文本是什么。
INDIRECT 是易失性函数吗?
是的。工作簿中任何地方发生变化,Excel 都会重新计算每一个 INDIRECT,因为它无法提前知道文本会指向哪些单元格。少量使用没有问题,成千上万个就会拖慢工作簿。INDEX 往往能完成同样的工作,而且不是易失性的。