SQL 数据分析 · 指南 · 2026年10月30日 · 11 分钟阅读

SQL 和 Excel 的区别:数据分析该用哪个,以及怎么从 Excel 转到 SQL

书桌一侧是电子表格,另一侧是数据库查询窗口,中间用一个箭头连起来

Excel 和 SQL 与其说是竞争对手,不如说是同一项工作不同阶段的工具。SQL 更擅长取数、关联和汇总数据:它能处理几百万行,直接读取数据所在的地方,而且一条查询就是你具体做了什么的书面记录,明天可以原样再跑一遍。Excel 更擅长查看、调整和展示一份小结果:假设分析模型、快速出图、手工修正,以及一个公司里谁都能打开的文件。大多数数据分析师每天两样都用:用 SQL 产出一张几百行的表,再用 Excel 或 BI 工具处理它。

如果你已经会用 Excel,你懂的 SQL 比你以为的多。数据透视表就是 GROUP BY,VLOOKUP 就是 JOIN,筛选就是 WHERE。本文把你熟悉的 Excel 操作逐一对应到 SQL,查询都在 Nomto SQL 课程的航空公司数据库上运行(104 个机场、33,121 个航班、262,788 笔订单,金额单位为美元)。下面每张结果表都是真实输出。

简短的答案:什么时候用哪个

任务 更适合 原因
从公司数据库取数 SQL 数据就在那里;导出是一个会过时的手工步骤
超过大约一百万行 SQL 一张 Excel 工作表最多只能放 1,048,576 行
关联多张表 SQL 一个 JOIN 代替每张表一列查找公式
每周都要重做的报表 SQL 重新运行查询即可,不会漏掉哪一步复制粘贴
核查某个数字是怎么算出来的 SQL 查询本身就是完整的配方
假设分析和财务模型 Excel 改一个单元格,所有相关数字跟着更新
快速看一眼一个小文件 Excel 打开、排序、扫一眼,完事
手工修改、备注、标颜色 Excel SQL 不能在结果里直接打字
五分钟内做好开会用的图表 Excel 内置功能,人人都熟悉
分享给不写代码的人 Excel 人人都有,都能打开

一条实用的规则:如果工作是「查找、合并、计数」,从 SQL 开始。如果工作是「摆弄这张表再拿给别人看」,用 Excel 就行,而且往往更好。

为什么行数上限比看起来更重要

在这个课程数据库里,ticket_flights(每位乘客每个航段一行)有 1,045,726 行,刚好塞得进一张工作表。App 事件表则完全放不下:

SELECT COUNT(*) FROM app_events;
count_star()
1494723

而且塞得进不等于用得顺手:一个有一百万行查找公式和计算公式的工作簿,重新计算会很慢。在 SQL 里,表的大小几乎不影响你怎么写查询。

筛选 → WHERE

在 Excel 里你点筛选箭头、勾选值。在 SQL 里你写出条件。8 月份下单、金额 1,000 美元及以上的订单,以及它们的总金额:

SELECT COUNT(*) AS bookings, SUM(total_amount) AS revenue
FROM bookings
WHERE book_date >= '2026-08-01'
  AND total_amount >= 1000;
bookings revenue
16081 29341684.00

对应关系:

Excel 筛选 SQL
勾选「Arrived」和「Departed」 WHERE status IN ('Arrived', 'Departed')
数字筛选:大于或等于 WHERE total_amount >= 1000
文本筛选:开头是 WHERE city LIKE 'Novo%'
日期筛选:介于 WHERE book_date >= '2026-08-01' AND book_date < '2026-09-01'
(空白) WHERE actual_departure IS NULL

有一个区别常让 Excel 用户栽跟头:在 SQL 里空单元格是 NULL,而 = NULL 永远匹配不到任何东西。要用 IS NULL。

排序和前 10 项 → ORDER BY 和 LIMIT

「降序排列,看前五名」写成:

SELECT book_ref, book_date, total_amount
FROM bookings
ORDER BY total_amount DESC
LIMIT 5;
book_ref book_date total_amount
3B54BB 2026-07-01 17:08:00 12045.00
3AC131 2026-07-27 01:06:00 10871.00
65A6EA 2026-06-29 06:28:00 10656.00
D7E9AA 2026-08-04 05:29:00 10628.00
EF479E 2026-07-29 15:58:00 10351.00

在 Excel 里,排序会改变工作表本身。在 SQL 里它只改变这一次的结果,表保持原样。

VLOOKUP / XLOOKUP → JOIN

在 flights 表里,机场和机型都只以代码出现。在 Excel 里你要加三列查找公式,每列指向另一张工作表。在 SQL 里,就是一个查询里的三个 JOIN:

SELECT f.flight_no,
       f.scheduled_departure,
       dep.city AS from_city,
       arr.city AS to_city,
       a.model
FROM flights f
JOIN airports  dep ON dep.airport_code = f.departure_airport
JOIN airports  arr ON arr.airport_code = f.arrival_airport
JOIN aircrafts a   ON a.aircraft_code  = f.aircraft_code
WHERE f.departure_airport = 'SVO'
  AND f.scheduled_departure >= '2026-08-01'
  AND f.scheduled_departure <  '2026-08-02'
ORDER BY f.scheduled_departure, f.flight_no
LIMIT 4;
flight_no scheduled_departure from_city to_city model
PG0120 2026-08-01 09:00:00 Moscow Mirny Boeing 737-300
PG0591 2026-08-01 09:00:00 Moscow Tomsk Sukhoi Superjet-100
PG0241 2026-08-01 09:40:00 Moscow Cheboksary Sukhoi Superjet-100
PG0677 2026-08-01 09:40:00 Moscow Makhachkala Boeing 737-300

注意同一张 airports 表被 JOIN 了两次,航班两端各一次,用了不同的别名。在 Excel 里,这相当于对同一张工作表做两次独立的查找。

有两种行为和 VLOOKUP 不同,而且都很重要:

没有匹配。 VLOOKUP 显示 #N/A。内连接 JOIN 会悄悄丢掉这一行。如果想保留它并留空,用 LEFT JOIN。下面就是那个没有任何航班的机型,内连接会把它藏起来:

SELECT a.model
FROM aircrafts a
LEFT JOIN flights f ON f.aircraft_code = a.aircraft_code
WHERE f.flight_id IS NULL;
model
Airbus A320-200

多个匹配。 VLOOKUP 返回第一个匹配,忽略其余的。JOIN 返回所有匹配,每匹配一次就重复一次这一行。一笔订单最多可以有五张机票:

SELECT b.book_ref, b.total_amount, COUNT(t.ticket_no) AS tickets
FROM bookings b
JOIN tickets t ON t.book_ref = b.book_ref
GROUP BY b.book_ref, b.total_amount
ORDER BY tickets DESC, b.book_ref
LIMIT 3;
book_ref total_amount tickets
070133 1133.00 5
070682 8012.00 5
111C34 2120.00 5

所以,如果你把订单和机票 JOIN 起来再对 total_amount 求和,每笔订单会按机票张数被重复计算:

SELECT (SELECT SUM(total_amount) FROM bookings) AS correct,
       SUM(b.total_amount) AS after_join
FROM bookings b
JOIN tickets t ON t.book_ref = b.book_ref;
correct after_join
207669809.00 343206192.00

这是从 Excel 转过来的人最常犯的 SQL 错误,因为 VLOOKUP 从不会让行数翻倍。JOIN 之前先问自己:左边的一行,在右边最多能匹配到几行?SQL JOIN 用法详解 对此有详细讲解。

数据透视表 → GROUP BY

「行」区域 = GROUP BY 的列;「值」区域 = 聚合函数。按舱位统计收入,以及每个舱位占总收入的比例(在透视表里就是「值显示方式:总计的百分比」):

SELECT fare_conditions,
       COUNT(*)    AS segments,
       SUM(amount) AS revenue,
       ROUND(100.0 * SUM(amount) / SUM(SUM(amount)) OVER (), 1) AS pct_of_revenue
FROM ticket_flights
GROUP BY fare_conditions
ORDER BY revenue DESC;
fare_conditions segments revenue pct_of_revenue
Economy 920793 146956844.00 70.8
Business 107642 55051796.00 26.5
Comfort 17291 5661169.00 2.7

这个查询扫描了一百多万行。SUM(SUM(amount)) OVER () 是一个窗口函数,它把总计放在每个分组旁边;原理见 SQL 窗口函数详解。

带「列」区域的透视表(状态往下排、月份往右排),就是每一列写一个条件计数:

SELECT status,
       COUNT(*) FILTER (WHERE EXTRACT(MONTH FROM scheduled_departure) = 7) AS jul,
       COUNT(*) FILTER (WHERE EXTRACT(MONTH FROM scheduled_departure) = 8) AS aug,
       COUNT(*) FILTER (WHERE EXTRACT(MONTH FROM scheduled_departure) = 9) AS sep,
       COUNT(*) AS total
FROM flights
GROUP BY status
ORDER BY total DESC;
status jul aug sep total
Arrived 10821 5886 0 16707
Scheduled 0 10345 5038 15383
On Time 0 518 0 518
Cancelled 5 6 403 414
Departed 0 58 0 58
Delayed 0 41 0 41

说实话,这里 Excel 更方便:透视表会自动生成各列,而在 SQL 里你得一列列写出来。很多分析师正是这样分工的:SQL 产出长表(状态、月份、计数),再由 Excel 或 BI 工具里的透视表把它展开成列。

透视表的「筛选」区域就是 WHERE(在分组之前),而「只显示合计超过 N 的组」就是 HAVING。见 GROUP BY 和 HAVING 的区别。

公式 → 表达式

Excel SQL
=A2*B2、=ROUND(A2, 2) 在 SELECT 里写 price * qty、ROUND(amount, 2)
=IF(A2>=1000, "large", "small") CASE WHEN total_amount >= 1000 THEN 'large' ELSE 'small' END
=IFERROR(A2/B2, "") a / NULLIF(b, 0)
=COUNTIF(range, "Cancelled") COUNT(*) FILTER (WHERE status = 'Cancelled')
=SUMIFS(amount, class, "Business") SUM(amount) FILTER (WHERE fare_conditions = 'Business')
=A2 & " " & B2 a || ' ' || b
=LEFT(A2, 3)、=UPPER(A2)、=TRIM(A2) LEFT(s, 3)、UPPER(s)、TRIM(s)
=EOMONTH、=YEAR、日期相减 =A2-B2 DATE_TRUNC、EXTRACT(YEAR FROM d)、d1 - d2
删除重复项 SELECT DISTINCT / COUNT(DISTINCT col)
累计求和列 =C1+B2 SUM(x) OVER (ORDER BY day)

思维上最大的转变是:Excel 公式写在一个单元格里,然后往下拖。SQL 表达式只写一次,就作用于每一行。嵌套的 IF 变成一个 CASE,从上往下读:

SELECT book_ref, total_amount,
       CASE WHEN total_amount >= 1000 THEN 'large'
            WHEN total_amount >= 300  THEN 'medium'
            ELSE 'small'
       END AS size
FROM bookings
ORDER BY book_ref
LIMIT 4;
book_ref total_amount size
00000F 2657.00 large
000012 379.00 medium
000068 181.00 small
000181 1318.00 large

而你会在旁边加一列、再按它做透视的那一步,在 SQL 里只是多一个 GROUP BY:

SELECT CASE WHEN total_amount >= 1000 THEN 'large'
            WHEN total_amount >= 300  THEN 'medium'
            ELSE 'small'
       END AS size,
       COUNT(*) AS bookings
FROM bookings
GROUP BY size
ORDER BY bookings DESC;
size bookings
medium 130009
small 68305
large 64474

删除重复项,比如有机场的城市一共有多少个:

SELECT COUNT(*) AS airports, COUNT(DISTINCT city) AS cities
FROM airports;
airports cities
104 101

Excel 真正占优的地方

这一点值得说实话,因为「SQL 更好」并不是在所有事情上都成立:

SQL 给你的回报是可复现性。一张经过二十步手工操作的表格很难核查或重建;而一条查询可以逐行阅读,在下个月的数据上重新运行,也能让同事审查。

怎么转:一条实用路径

  1. 学会理解「一行」。 每次写查询之前,先弄清每张表的一行代表什么(一个航班、一笔订单、一个机票航段)。这取代了上下滚动工作表的习惯。
  2. 从你在 Excel 里本来就做的事开始。 筛选 → WHERE,排序 → ORDER BY,透视 → GROUP BY。把你每周真实要做的一份报表用 SQL 重做一遍。
  3. 然后是 JOIN。 替换掉你的 VLOOKUP,每次 JOIN 前后都检查行数。
  4. 最后一步留给 Excel。 把很小的最终结果导出到工作表里做图表和备注。这不是偷懒,大多数分析师就是这么工作的。
  5. 基础用熟之后,再加上 CASE、CTE 和窗口函数。 SQL 速查表 把它们都放在了一页上。

在 Nomto 的 SQL 练习场里,你可以直接在浏览器里对航空公司数据库运行这些查询,什么都不用安装,课程也正是从这些类似 Excel 的操作开始的:选列、筛选、排序和分组。SQL 基础查询语句 是很好的入门读物。

常见问题

SQL 比 Excel 难学吗?

基础部分不难。如果你会做数据透视表、会用 VLOOKUP,几周之内就能学会 SELECT、WHERE、GROUP BY 和 JOIN。需要练习的是用整张表而不是单个单元格来思考,以及察觉 JOIN 什么时候让行数翻倍。

SQL 能完全取代 Excel 吗?

取数和汇总,基本可以。建模、手工修改和快速展示,不能。大多数分析师用 SQL 产出一份小结果,再用电子表格或 BI 工具来处理它。

数据分析师还用 Excel 吗?

用,而且很普遍,尤其是分析的最后一步和分享结果的时候。SQL 负责取数据;大家最终看到的,往往是 Excel、Google Sheets 或 BI 工具。

VLOOKUP 在 SQL 里对应什么?

对查找列做 JOIN:FROM flights f JOIN aircrafts a ON a.aircraft_code = f.aircraft_code。如果想像 VLOOKUP 那样保留没有匹配的行(VLOOKUP 会保留这一行并显示 #N/A),用 LEFT JOIN。

其他语言: English, Español, Português (Brasil), Tiếng Việt