SORT 和 SORTBY:排序交给公式
排序大概是所有人学会的第一个 Excel 操作:选中区域,点一下 A 到 Z,或者自定义排序里加个主要关键字、次要关键字。但只要你做过需要反复更新的报表,就一定被它坑过——源数据加了几行,上次排好的顺序立刻失效;想保留原表不动、只把排好序的结果放到另一个地方,就得复制粘贴一遍;更麻烦的是,排序会真的把行的物理位置改掉,一旦忘了先备份,原来的录入顺序就再也找不回来了。SORT 和 SORTBY 就是为了解决这类问题而生的:它们返回的是一个数组,原表纹丝不动,源数据变化时顺序自动重排,而且排序逻辑写在公式里,谁看都能看懂。
这两个函数的区别在于分工。SORT 是按“结果区域自己的某一列”排序,简单直接;SORTBY 是按“另一组独立的区域”排序,那组区域甚至可以不在返回结果里。听起来 SORTBY 更复杂,但在真实场景里它反而用得更多,因为很多排序依据并不想出现在结果里——比如按销售额排名,但结果只展示客户名称和城市;或者按一个辅助列排,而辅助列本身是公式算出来的。掌握这两个函数的先后顺序建议是:先会用 SORT,再体会 SORTBY 解放了什么。
一、SORT:四个参数一次说清

SORT 的语法写在下面的代码块里,一共四个参数,日常只用到前三个。
SORT(array, [sort_index], [sort_order], [by_col])
第一个参数 array 是要排序的区域。第二个参数 sort_index 是按第几列排,注意它写的是“在 array 里的第几列”而不是工作表的列号,如果你排的是 C2:F500,写 2 代表按 D 列排。省略时默认按第一列。第三个参数 sort_order 是方向,1 表示升序、-1 表示降序,省略时默认 1。第四个参数 by_col 决定是按行排还是按列排,省略或 FALSE 时按行排,写 TRUE 时按列排,用法和 UNIQUE 里的同名参数一致。
最容易搞混的是第二个参数的计数方式。假设你在 H1 写 =SORT(C2:F500, 2, -1),这里的 2 指的是 C 到 F 这个区域里的第二列,也就是工作表的 D 列,而不是工作表的 B 列。很多人第一次用时会当成工作表列号,结果排出来方向不对,查半天发现是列号理解错了。养成一个习惯:数的时候从 array 的左上角开始数起,第一列就是 1。
关于稳定性有个细节值得知道:SORT 的排序是稳定的,也就是说当排序依据相同时,这些行会保持它们在源数据里的原始先后次序。这个特性非常有用,因为它意味着嵌套 SORT 的写法是可靠的——先按次要关键字排一遍,再按主要关键字排一遍,次要关键字的次序不会因为第二轮排序而被打乱。事实上这正是多关键字排序的底层原理,很多数据库和编程语言的排序函数却不保证这一点,Excel 这里算是给了一个额外的便利。
还有一点要注意:SORT 只支持单关键字排序,不像自定义排序对话框可以加主要关键字、次要关键字。想做多关键字排序,要么用 SORTBY(它天然支持多组排序依据),要么把 SORT 嵌套起来用。嵌套的写法有个窍门:先排次要关键字,再把结果作为主要关键字排序的输入,因为稳定的排序会保留上一轮的顺序。
二、SORTBY:真正好用的是它
SORTBY 的语法更灵活,写在下面的代码块里,排序依据可以写好多组。
SORTBY(array, by_array1, [sort_order1], [by_array2, [sort_order2]], ...)
第一个参数 array 同样是要排序的区域,之后是成对出现的“排序依据区域”和“排序方向”,最多可以写一百多组。关键在于 by_array1 这些依据区域只要行数和 array 一致就行,完全不需要出现在 array 里。这一点是 SORTBY 相对 SORT 最大的解放:你可以按隐藏的辅助列、按别的表的列、甚至按一个临时算出来的数组来排序。
举个例子,=SORTBY(B2:C500, D2:D500, -1) 表示返回 B 列和 C 列,但按 D 列的金额从大到小排。结果里根本没有 D 列,却完全按 D 列的顺序走。再比如 =SORTBY(A2:F500, C2:C500, 1, D2:D500, -1) 是先按城市升序、城市相同的再按金额降序,这就是多关键字排序,写起来比嵌套 SORT 清爽得多,也是日常最推荐的写法。
SORTBY 还有一个杀手锏:排序依据可以是动态计算的数组。=SORTBY(B2:C500, D2:D500/E2:E500, -1) 按单价排序,而单价这个字段在原表里根本不存在;=SORTBY(B2:C500, RANDARRAY(ROWS(B2:C500)), 1) 可以随机打乱顺序,用来做抽签或者随机抽样非常方便。这种“依据可以是任意计算结果”的特性,让 SORTBY 成了动态数组家族里最能发挥想象力的一个。
三、五个能直接抄的写法
下面这张表列出了五种最常见的排序需求,公式都可以直接复制,替换区域即可使用。第三行和第五行是日常工作里用得最多的两个。
| 需求 | 可复制的写法 | 要点 |
|---|---|---|
| 单列升序 | =SORT(B2:B500) |
参数全省略,默认第一列升序 |
| 按第 4 列降序 | =SORT(A2:F500, 4, -1) |
列号从 array 左上角数起 |
| 按不在结果里的列排 | =SORTBY(B2:C500, D2:D500, -1) |
依据列可以不出现在结果中 |
| 多关键字排序 | =SORTBY(A2:F500, C2:C500, 1, D2:D500, -1) |
先城市升序、再金额降序 |
| 按自定义顺序排 | =SORTBY(A2:F500, MATCH(C2:C500, {"华东";"华南";"华北"}, 0), 1) |
用 MATCH 生成优先级序号 |
第五行是个很有价值的高级写法。Excel 的默认排序只能按拼音或者笔画,如果你想按“华东、华南、华北”这种业务上的固定顺序排,就需要先用 MATCH 把每个值映射成一个序号,再按序号排。这个套路同样适用于按月份名称排(避免四月排在二月前面)、按职务高低排、按项目阶段排。核心思路永远一样:先把文本变成数字序号,再按数字排。
第四行也可以写成嵌套 SORT 的形式:=SORT(SORT(A2:F500, 4, -1), 3, 1),先按金额降序、再按城市升序。两种写法结果相同,但 SORTBY 可读性更好,参数一多时优势尤其明显。建议统一用 SORTBY,只在排序依据恰好就是结果区域里某一列的简单场景下用 SORT,这样公式更短。
四、真实场景
第一个场景是排行榜。做“本月销售前十”这类报表,写法是 =TAKE(SORTBY(B2:C500, D2:D500, -1), 10),先按金额降序排好,再取前 10 行。如果还要加排名列,可以在旁边写 =SEQUENCE(ROWS(H2#)) 生成 1 到 10 的序号。整套做法不需要任何辅助列,源数据新增时排行榜自动重排,比手工排序加复制稳定得多。
第二个场景是给下拉菜单排序。前一讲里我们用 UNIQUE 生成客户清单,但那个清单的顺序取决于客户在源数据里第一次出现的顺序,看起来很乱。改成 =SORT(UNIQUE(B2:B500)) 就能得到按拼音排好序的清单,再把它作为数据验证的来源,下拉选项就整整齐齐。如果要按“客户金额从大到小”排,写成 =SORTBY(UNIQUE(B2:B500), SUMIF(B2:B500, UNIQUE(B2:B500), D2:D500), -1),排序依据是现算的汇总值。
第三个场景是按自定义顺序排列月份或者阶段。项目进度表常常要按“立项、开发中、测试、上线”排序,直接按拼音排会得到莫名其妙的顺序。用上一节第五行的 MATCH 写法就能解决,把顺序写成一个常量数组放在公式里。如果顺序经常变,更稳妥的做法是单独建一张“顺序对照表”,公式里引用那张表的区域,改顺序时只改对照表,不用动公式。
第四个场景是随机抽样和分组。做质检抽查时,用 =TAKE(SORTBY(A2:F500, RANDARRAY(COUNTA(A2:A500)), 1), 20) 就能随机抽出 20 行,按一次 F9 换一批。注意 RANDARRAY 是易失函数,每次重算都会变,所以抽好之后要把结果复制成数值固定下来,否则下次打开文件名单就变了。这类“用完即固化”的操作一定要记得及时粘贴为值。有关排序结果如何被别的函数继续取用,可以配合 UNIQUE:去重不用再点删除重复项 和 FILTER:按条件把行整条捞出来 一起练。
第五个场景是给合并后的多表数据排序。如果各分公司的明细用 VSTACK 堆在了一起,堆完的顺序是分公司一块一块的,看起来很乱,此时在外面套一层 SORTBY 就能统一按金额或者日期重排:=SORTBY(VSTACK(北京!A2:F500, 上海!A2:F500), VSTACK(北京!D2:D500, 上海!D2:D500), -1)。注意排序依据也要跟着一起纵向拼接,行数必须和合并后的总行数一致,这是这类公式唯一需要小心的地方。
第六个场景是做“Top N 加其他”的报表。常见的需求是列出前五大客户,剩下的全部归到“其他”一行。做法是先用 =TAKE(SORTBY(...),5) 取前五,再用 SUM 减去这五家的金额算出剩余值,手工拼一行“其他”。因为前五名的范围是动态的,这个“其他”行的数值也会跟着变,整张报表始终自洽。类似的思路还能用于“前 80% 客户贡献了多少金额”这类帕累托分析。做这类分析时往往还要给出名次列,用 =SEQUENCE(ROWS(H2#)) 就能顺着溢出区域自动生成 1、2、3 一路排下去,比手工填序号再拖动省事,而且行数变化时序号自动增减。想把这个造序号的能力用得更全面,可以接着读 SEQUENCE:造序列造日期造日历。
五、翻车提醒、版本要求与老版本替代

先说翻车点。第一,排序方向参数写错成 0 会报错,只能是 1 或者 -1,写 0 会返回 #VALUE!。第二,SORTBY 的依据区域行数必须和 array 一致,写成整列或者范围不一致都会报“数组大小不匹配”。第三,区域内如果混了数字和文本,Excel 会按“数字在前、文本在后”的默认规则排,不会出现错误但结果可能不是你想要的,建议先用分列或者 VALUE 把类型统一。第四,排序结果溢出到下方时同样会撞上 #SPILL!,把结果放在独立区域最省事。
第二,中文排序的默认是按拼音,这一点在“排序”对话框里可以改成按笔画,但 SORT 函数没有这个开关。如果需要按笔画排序,只能借助辅助列用比较冷门的方式实现,日常几乎用不到,遇到时建议直接在“排序”对话框里手工做一次。第三,空白单元格在升序时会排在最前面,降序时排在最后面,这个行为和“排序”对话框一致,但和很多人预期相反,做报表时留意一下。
版本方面,SORT 和 SORTBY 与 UNIQUE、FILTER 同属动态数组家族,需要 Microsoft 365 订阅版或者 Excel 2021 及以后版本。Excel 2019、2016 及更早版本不支持,公式会显示为 #NAME?。这四个函数是同一批发布的,所以能用其中一个就说明另外几个也都能用,反过来也一样——判断版本是否支持时,测一个就够了。
老版本要替代,有四条路。最简单的是“排序”对话框,能用但结果不自动更新,而且会改动原表。第二条是 SMALL 加 INDEX 的数组公式组合:=INDEX($B$2:$B$500, MATCH(SMALL($D$2:$D$500, ROW(A1)), $D$2:$D$500, 0)),按 Ctrl+Shift+Enter 输入后向下填充,可以取出按金额升序排列的客户名,缺点是并列值会出错、还要预先拖够行数。第三条是用 RANK 加辅助列生成名次,再按名次排序,最稳妥但要占一列。第四条是透视表,把要排序的字段拖进值区域,用透视表自带的排序功能,刷新即可更新,在老版本里这是最接近动态排序的方案。
如果你的排序需求还牵涉到“按条件先筛再排”,那顺序一定是先 FILTER 后 SORTBY,写成 =SORTBY(FILTER(...), ...) 的形式,因为要先减少行数、再决定顺序。反过来写虽然不会报错,但会先排一堆用不到的行,白白浪费计算量。多条件构造不太熟的话,可以参考 多条件查找的四种解法对比 里讲的条件构造思路,两者底层逻辑是相通的。
常见问题
SORT 的第二个参数到底写工作表的列号还是区域的列号?
写的是区域内部的列号,从 array 的左上角开始数。比如 =SORT(C2:F500, 2, -1) 里的 2 指的是 C 到 F 这个区域里的第二列,也就是工作表的 D 列,不是 B 列。这是最常见的踩坑点,尤其在只处理部分列的时候。避免出错的习惯是:先确认 array 的第一列是哪一列,然后从左往右数。如果你经常搞混,干脆改用 SORTBY,直接写依据区域的地址,不用数数。
我想做多关键字排序,SORT 做不到吗?
SORT 一次只能指定一个关键字,但有两种办法实现多关键字。第一种是用 SORTBY,把多组依据依次写下去:=SORTBY(A2:F500, C2:C500, 1, D2:D500, -1) 表示先按城市升序、城市相同再按金额降序,这是推荐写法。第二种是嵌套 SORT,先排次要关键字再排主要关键字:=SORT(SORT(A2:F500, 4, -1), 3, 1)。两种结果一致,但 SORTBY 可读性更好,关键字越多优势越明显。
排序结果里有空白行,是被排到最前面了吗?
是的。升序时空单元格排在最前面,降序时排在最后面,这个行为和“排序”对话框完全一致。原因是空值在 Excel 的排序规则里被视为最小值。如果你不希望看到这些空白行,先过滤再去重或者排序:=SORT(FILTER(B2:B500, B2:B500<>""))。如果源数据里空行是公式返回的空字符串,同样的写法依然有效;如果是真正的 0,需要再加一个不等于 0 的条件。
能不能按我想要的业务顺序排,比如华东、华南、华北?
可以,思路是先用 MATCH 把文本映射成序号,再按序号排:=SORTBY(A2:F500, MATCH(C2:C500, {"华东";"华南";"华北"}, 0), 1)。MATCH 会返回每个值在常量数组里的位置,华东是 1、华南是 2、华北是 3,排序就按这个序号走。如果顺序经常调整,建议把 {"华东";"华南";"华北"} 换成一张对照表的区域引用,改顺序时只改对照表,公式不用动。
排序结果能不能直接被其他公式引用?
可以,而且这是它相对“排序”对话框最大的优势。溢出出来的整片区域可以用左上角单元格加井号来引用,比如结果在 H2 就写 H2#,引用它会得到整个区域,行数变化时引用范围自动跟着变。于是你可以写 =SUM(INDEX(H2#,0,2)) 对结果区域第二列求和,或者写 =ROWS(H2#) 统计有多少行。把排序结果当成一片“虚拟的、会自己长大的表”来用,是动态数组时代最重要的工作方式之一。
SORT 和 SORTBY 到底该用哪个?
一句话判断:排序依据就在你要返回的那片区域里,用 SORT;排序依据不在结果里、或者是现算出来的、或者有多个关键字,用 SORTBY。实际工作里 SORTBY 用得更多,因为“按销售额排名但只展示客户名”这类需求太常见了。唯一的例外是简单的一列排序,=SORT(B2:B500) 比 =SORTBY(B2:B500, B2:B500, 1) 短得多,写起来也直观。
为什么我用 RANDARRAY 排出来的顺序每次都在变?
因为 RANDARRAY 是易失函数,每次工作表重算都会生成一组新的随机数,排序结果自然跟着变。这在随机抽样时是想要的效果,但名单确定之后就必须固化:选中结果区域,复制,再选择性粘贴为数值。忘记固化是最常见的翻车,表现为第二天打开文件发现抽查名单全变了。如果只想要一个稳定的伪随机顺序,可以在抽好之后把 RANDARRAY 换成那一列的实际数值。
