LET:给长公式里的中间值起名字
长公式为什么这么难养活
先来看一条真实存在的公式,它出现在一家公司的提成计算表里:=IF(ISNA(VLOOKUP(A2,基础表!$A:$D,4,0)),0,VLOOKUP(A2,基础表!$A:$D,4,0)*IF(VLOOKUP(A2,基础表!$A:$D,3,0)>10000,1.2,1)*IF(MONTH(C2)<=6,0.95,1))。三行屏幕宽度,同一个 VLOOKUP 写了三遍,改一次提成规则要同时改三处,改漏一处就悄悄算错。三个月后写它的人自己也读不懂了。
长公式有三个毛病,一个比一个致命。第一个是重复计算:同一段表达式出现多次,Excel 就要算多次,数据量一大,重算时间成倍上涨。第二个是不可读:读者必须先在大脑里维护一个栈,从左到右一层层剥,稍有分心就断线。第三个是难维护:需求一变,你得在长字符串里找到所有需要改的地方,而它们往往长得一模一样,靠眼睛根本分不出哪两处是同一个意思。
在 LET 出现之前,人们用三种办法对付它。加辅助列,把中间结果落到单元格里,可读性好但会弄脏表格结构;用名称管理器,把一段表达式定义成名称,干净但名称散落在工作簿级别,改起来要打开对话框;或者干脆接受长公式,然后祈祷自己别离职。三种办法都有代价。辅助列会让表格横向膨胀,一张本来十列的表可能变成二十列,打印和筛选都跟着受罪;名称管理器把逻辑藏在一个小对话框里,接手的人根本不知道还有这么个东西存在,改了一次就出事;至于接受长公式,代价会在半年后集中爆发,那时没人记得当初为什么这么写。
更现实的一点是协作成本。长公式是单人作品,别人不敢碰;辅助列是公共财产,谁都能看懂但谁都能改坏;名称管理器介于两者之间,看得见但摸不着。一个团队里如果同时存在这三种风格,交接时必然鸡同鸭讲。LET 的价值不只在于让公式变短,更在于它给出了一套所有人都一样的组织方式:名字加值加结果,走到哪儿都是这个结构。
LET 给出的方案极其朴素:允许你在一条公式内部定义若干名字,先算好存起来,最后再使用。名字的作用范围仅限这一条公式,不占用单元格,也不污染名称管理器。于是上面那条公式可以重写成先查一次、存成“基础值”和“档位”,再按规则计算,VLOOKUP 只出现一次,逻辑一眼看穿。
语法:参数成对出现,最后一笔是结果

LET 的语法是 =LET(名称1,值1,名称2,值2,...,结果表达式)。它的参数个数不固定,但结构固定:前面全是成对的“名字加值”,最后一个参数单独出现,作为整条公式的最终返回值。比如 =LET(半径,5,面积,3.14*半径*半径,面积*2),定义了半径和面积两个名字,最后返回面积的两倍。
几个必须记住的规则。名字要符合 Excel 的命名规范:不能以数字开头,不能包含空格和大多数标点,不能长得像单元格地址,比如不能叫 A1 或 B10,也不能用单个字母 r、c、R、C 这类容易和行列标记混淆的名字。名字之间可以互相引用,但只能引用在它之前定义的,不能往后引用,也不能循环引用自己。
值可以是任何东西:常量、单元格引用、区域、函数结果、甚至另一个 LET 或 LAMBDA。这意味着你可以先定义“数据区”为 FILTER(...) 的结果,再在后面的参数里对这个数据区做统计,逻辑层次一目了然。每个名字最多能定义 126 组,日常使用远远用不完。
最后一个参数的地位很特殊。它前面没有配套的名字,Excel 把它当成“算完之后交出来的东西”。很多人第一次写 LET 会在这里犯错:写完最后一对名字和值就收括号,结果函数报参数数量不对。记住一条:LET 的参数总数一定是奇数,前面成对,最后落单。
理解 LET 的关键在于把它想成一段微型程序:先声明变量,再执行计算,最后 return。它和编程里的局部变量几乎是一回事,只是写在同一行里。一旦建立这个心智模型,写长公式的思路会彻底改变,从“我该怎么把这么多层套进去”变成“我要先算出哪几个中间量”。
再补充两条实用的书写习惯。第一,公式太长时可以在编辑栏里用 Alt+Enter 换行,把每一对名字和值放在单独一行,Excel 完全接受带换行的公式,读起来舒服很多。第二,名字的顺序要按计算依赖排,先算的写前面,后算的引用前面的结果,千万不要跳着写,否则三个月后你自己都要从头推一遍才能看懂。
五个改造案例,从长到短

案例一,消灭重复的查找。原始公式 =IF(ISNA(VLOOKUP(A2,表!$A:$D,4,0)),0,VLOOKUP(A2,表!$A:$D,4,0)*1.2) 改造后:
=LET(查得,VLOOKUP(A2,表!$A:$D,4,0),IF(ISNA(查得),0,查得*1.2))
查找只做一次,找不到时返回 0,找到时乘 1.2,逻辑清楚得像说话。
案例二,拆分日期计算。把 DATEDIF 重复三次的拼接公式改写成 =LET(年,DATEDIF(A2,TODAY(),"Y"),月,DATEDIF(A2,TODAY(),"YM"),年&"年"&月&"个月")。原本挤在一起的三个函数调用被拆成两行声明加一行输出,改单位时不会漏改。这个场景在AGGREGATE:会跳过错误的统计那类容错统计里同样常见。
案例三,缓存筛选结果再做统计。=LET(数据,FILTER(A2:D5000,D2:D5000>0),行数,ROWS(数据),总额,SUM(INDEX(数据,0,3)),"共"&行数&"行,合计"&总额&"元")。先把筛选结果存成“数据”,之后引用它三次而只筛选一次,性能提升非常明显。
案例四,把判断条件抽出来。=LET(是否大单,B2>10000,是否华东,C2="华东",折扣,IF(是否华东,0.9,1)*IF(是否大单,0.95,1),B2*折扣)。条件被命名后,公式读起来像业务规则说明书,业务同事也能看懂个大概。
案例五,配合错误处理。=LET(结果,XLOOKUP(A2,编码列,名称列,"未找到"),IF(结果="未找到","请核对编码",结果))。查找和兜底分离,改提示文案不用碰查找逻辑。
案例六,把一整块业务规则封装好,方便以后直接搬进 LAMBDA。比如阶梯提成的计算:先定义“销售额”“档位”“费率”三个名字,档位用 IFS 判断,费率用 XLOOKUP 查表,最后返回销售额乘以费率。写成 LET 之后,你会发现这条公式已经具备了函数的雏形,只要在最外面套一层 LAMBDA 并把参数换成销售额,就能变成可以复用的自定义函数。这也正是 LET 与 LAMBDA 天然衔接的原因。
改造完之后别忘了做一次对照校验:把新旧两条公式并排放在两列,对几百行数据逐行比对,结果完全一致再删掉旧公式。这个习惯能救你很多次,尤其是在改造涉及浮点运算或者除法的时候。
性能与可读性:什么时候值得用
先说性能。LET 最实质的收益不是好看,而是“同一段只算一次”。凡是公式里出现两次以上的昂贵计算,都该考虑提出来:大范围的 VLOOKUP、整列的 SUMPRODUCT、FILTER 出来的动态数组、跨工作簿的引用。一条公式里 VLOOKUP 出现三次,改成 LET 之后就只查一次,重算耗时会降到原来的三分之一左右。在有几万行数据的表里,这个差距能从“点一下卡三秒”变成“点一下就出来”。
但 LET 不是万能加速器。如果每个名字只被用一次,把它提出来不会带来任何性能收益,纯粹是为了可读性。可读性本身当然是价值,只是要清楚自己图的是什么,别指望靠它把一张设计糟糕的表救回来。真正卡顿时,先检查有没有整列引用、有没有大量易失函数、有没有跨工作簿链接,这些才是大头。想系统排查这类问题,可以翻到本书后面讲性能的那一篇,里面列了完整的排查顺序和替代清单。
另外要区分“单次计算成本”和“触发次数”。一条 LET 公式就算写得再漂亮,只要它所在的一整列有上万行,每次重算都要跑上万次,累积起来依然可观。遇到这种情况,把中间结果下沉到辅助列、让上万行共享同一份计算,往往比在每条公式里做局部优化有效得多。
再说可读性。判断该不该用 LET 的经验标准很简单:如果一条公式长到需要横向滚动才能看全,或者同一个表达式出现了两次以上,就该改造。反过来,如果公式本来就只有十几个字符,套一层 LET 只会让它更长,属于过度设计。
和另外三种方案的对比如下,选择时可以照着这张表来。
| 方案 | 作用范围 | 是否占用单元格 | 适合场景 |
|---|---|---|---|
| LET | 单条公式内部 | 否 | 长公式内复用中间值 |
| 名称管理器 | 整个工作簿 | 否 | 多处公式共用同一段逻辑 |
| 辅助列 | 工作表 | 是 | 需要逐步核对、给他人看过程 |
| LAMBDA | 定义为自定义函数 | 否 | 逻辑要在多处反复调用 |
作用域、限制与老版本替代
LET 的名字只在当前这条公式里有效。这意味着同一个名字可以在不同单元格里反复使用而互不干扰,也意味着你没法在别的公式里引用它。如果需要跨单元格共用,那就该用名称管理器,把表达式定义成工作簿级别的名称,之后所有公式都能引用,相关玩法在命名公式与名称管理器的进阶玩法里有展开。
还有几个限制值得提前知道。LET 定义的名字不能用于需要“区域引用”的函数的某些场合,比如你不能用它去构造一个供 SUMIF 使用的条件区域,除非那个名字的值本身就是区域;名字里不能放易变的东西还指望它只算一次,比如把 TODAY() 定义成名字,它在同一条公式里仍然是每次求值时重算。
调试方面有个小技巧:临时把最后一个参数换成某个中间名字,比如把结果表达式改成“数据”,就能看到中间值的计算过程,确认无误后再改回去。这比按 F9 看片段更方便,因为不需要反复选中再按 Esc。
还有一条容易被忽略的限制:LET 无法突破 Excel 公式 8192 字符的总长度上限。当你把一段长公式拆成名字加值的形式时,总字符数通常不降反升,因为每个名字都要写两遍。所以遇到接近上限的超长公式,别指望靠 LET 塞进去,正确做法是拆成辅助列或者干脆用 LAMBDA 定义在名称管理器里,把公式主体搬出单元格。
版本要求必须说清楚:LET 从 Microsoft 365 和 Excel 2021 开始提供,Excel 2019、2016 及更早版本完全没有,打开含 LET 的文件会显示 #NAME?。WPS 的部分新版已经支持,但覆盖不全。如果你的文件要发给版本不明的同事,稳妥做法是保留一份辅助列版本。版本差异的完整清单见版本对照:新函数在老 Excel 里怎么办。
老版本的替代方案有三条。辅助列最直白,把每个中间值各占一列,公式都变短,代价是表格变宽;名称管理器次之,把一段表达式定义成名称,其他地方引用名称,效果接近 LET 但配置分散;嵌套最无奈,只能接受长公式,靠缩进和换行(Alt+Enter 在公式里换行)勉强维持可读。
常见问题
为什么我的 LET 提示参数个数不对
先确认版本。如果打开文件时结果直接是 #NAME?,那不是参数问题,而是你的 Excel 根本不认识 LET,它把整个函数名当成了未定义的名称。LET 需要 Microsoft 365 或 Excel 2021 及以上,Excel 2019 及更早版本一律不支持。确认版本没问题之后,再来看参数结构:参数总数必须是奇数。前面每定义一个名字都要紧跟它的值,最后再加一个单独的结果表达式。最常见的错误是写完最后一对名字和值就直接收括号,忘了写返回值;或者在某处漏了一个值,导致配对错位。检查办法是从左往右数逗号,成对部分每个名字后面紧跟一个值,最后一个参数后面不该再有名值对。Excel 的输入提示会在你键入逗号时显示下一个参数名,盯着它写基本不会错。
名字能不能用中文
可以,而且推荐。Excel 的命名规范允许中文字符开头,名字里也能用中文,只要不包含空格和特殊符号即可。写成 =LET(单价,B2,数量,C2,单价*数量) 比写成 =LET(p,B2,q,C2,p*q) 直观得多,交接时别人一眼就懂。唯一要注意的是别起太长的名字,公式栏宽度有限,八个字以内比较舒服。另外名字不能和单元格地址冲突,像“甲1”这种可能被误判的地址样式要避开。
一条公式里最多能定义多少个名字
官方上限是 126 组名字和值,参数总数上限同样受 Excel 公式整体 8192 字符的限制。实际使用中,超过十组名字的 LET 就已经很难读了,通常说明这条公式承担了太多职责,应该拆成两条或者交给 LAMBDA 封装。判断标准不是“能不能写进去”,而是“半年后你还能不能一眼看懂”,如果答案是否定的,再多名字也没意义。
LET 定义的名字能传给别的函数当区域吗
可以,只要那个名字的值是区域。比如 =LET(区,A2:A100,SUM(区)) 完全合法,SUM 收到的就是 A2:A100。甚至可以让值是动态数组的结果,=LET(区,FILTER(A2:A100,B2:B100>0),COUNTA(区)) 也成立。真正受限的是那些要求“必须是直接引用”的场合,比如条件格式里的数据有效性引用、图表的数据源,这些地方 LET 帮不上忙。
用了 LET 之后文件反而变卡是怎么回事
通常不是 LET 的锅,而是你把昂贵计算放进了名字里却仍在大数据量下重复调用整条公式。LET 只保证同一条公式内部不重复,不保证这一列几千行不各自算一遍。如果每一行的 LET 里都有一次全表 VLOOKUP,五千行就是五千次全表查找,照样慢。解决办法是把查找结果一次性算成辅助列,或者把源数据转成表格后用结构化引用,更彻底的方案是用 XLOOKUP 一次返回整列再向下溢出。
LET 和 LAMBDA 是什么关系
两者经常一起出现,但职责不同。LET 是一次性的,它把值存进名字供当前公式使用;LAMBDA 是可复用的,它把一段计算逻辑封装成一个可以反复调用的函数。写复杂公式时典型搭配是:先用 LAMBDA 定义通用逻辑并命名,再在具体单元格里用 LET 组织参数,两者结合能把过去需要几十层嵌套的需求压缩到两三行。想自己造函数的话,下一篇LAMBDA:自己造一个函数会接着讲。
