🏠 总目录📚 本教程 00 · 怎么用这份教程 →
📑 本页目录(点开跳转)

00 · 怎么用这份教程

⏱ 30 分钟 | ⭐ 先划清一件事:这里不教你运维数据库,只教你把问题写成查询


🎯 一句话

这套教程只做一件事:把「我想知道 X」翻译成一条跑得对、跑得完、你敢把结果发出去的 SQL。 建表、建索引、备份、扩容、连接池 —— 站内别的章节已经在讲,这里一句不重复。


⏱ 先说清楚这套的章比站内其他板块长(普遍 50–120 分钟,站内其他板块的中位是 30)—— 因为每个知识点都带实跑代码和真实报错,压不下去。设计上就没打算让你一次读完: 超过 55 分钟的章在中间有 🛑 休息点,最长的几章有两个,停在那里下次接着读就行。 徽章是按 170 字/分钟实测校准的,宁可吓到你,也不骗你。


🚦 一、先划清一件事

「学 SQL」这四个字底下其实塞了两件很不一样的事:

关心什么 谁在干
数据库怎么运起来 表怎么设计、索引怎么建、事务隔离级别、迁移、备份、连接池、扩容 后端 / DBA / 平台
⭐ 怎么把一个问题写成查询 这个数怎么算出来、这个连接会不会把账放大、这个 WHERE 到底挡掉了谁 所有需要看数的人

这套教程只做右边那件事。 判据很简单:如果一个问题的答案是「改表结构」或者「加台机器」,它不在这里; 如果答案是「把这条查询换个写法」,它在这里。

⭐ 为什么值得单独学:左边那件事你一年做不了几次,右边那件事你每天做十次。 而右边最贵的错误有一个共同形状 —— 不报错。查询跑完了,返回了一张漂亮的表,数字是错的, 没有任何一行日志告诉你。这套教程有一多半篇幅是在拆这类「不报错的错」。

🧯 站内已经有人 own 的四块,本教程一个字不重讲

⚠️ 这不是客气话,是分工。你要那几件事的时候,请直接去那边,别在这里找:

那件事 归谁 那边给了什么
索引怎么建 AI 全栈 · 06 关系数据库 建索引的判据、复合索引的列序、覆盖索引,以及一组 3.802 秒 → 0.0019 秒的实测
COUNT(*) 在大表上多贵 · 游标分页怎么用 · SQL 注入 AI 全栈 · 06b 列表接口与分页 分页接口的完整形状;⭐ 注入那一节整段让给它,本教程不重复
训练侧和线上侧的 SQL 为什么算出两个数 模型上线之后 · 04 训练推理一致性 训推不一致的七种形态
数据本身脏在哪 数据这一关 · 04 脏数据的十种形态 数据进模型之前的那一半

⭐ 本教程和它们的接缝是双向的:09 章会用到 06 章建好的索引(但只讲写法怎么把它废掉), 05 章会解释 06b 那个 (updated_at, id) < (?, ?) 到底是什么(那边 own 怎么用), 03 章会把《AI 全栈》15 章那句「同一张表的 GROUP BY 看板」真写出来(按 feature、按天×模型;每用户 Top-N 那类要等 07 章的窗口函数)。


📋 二、章节地图

12 页,正文合计约 17 小时(章内有 🛑 断点,设计上就是分次读)。⭐ 不必按顺序读完,下一节有四条路线。

# 章 ⏱ 一句话
00 怎么用这份教程 30 你在这里
01 一条查询是怎么跑的 54 SELECT 写在最前面,却几乎是最后才执行 —— 搞懂这个顺序,一半的报错自己就解释了
02 JOIN 的几种语义 78 ⭐ 实测:JOIN 之后 SUM 从 150 变成 250,没报错,账就这么错了
03 聚合与分组 146 COUNT(*) 是 3,COUNT(city) 是 2 —— 差的那一行去哪了
04 NULL 与三值逻辑 108 ⭐ 实测:NOT IN ('BJ', NULL) 返回空集,一行都没有,且不报错
05 子查询的三种形状 100 标量 / 行 / 表;IN、EXISTS、JOIN 到底该选哪个
06 CTE 与递归查询 80 ⭐ 血缘图就是一张边表,「全部上游」是一条递归查询
07 窗口函数 70 ⭐ GROUP BY 把十行压成一行,窗口函数让十行还是十行、但每行都知道自己排第几
08 窗口帧 106 ⭐ 「最近 3 行」和「最近 3 天」,数据有缺口时不是一回事
09 计划里的连接与索引失效 104 ⚠️ 索引在、计划里也写着索引名,它照样可能是全表扫
10 拿 SQL 审问一份数据 96 ⭐「每一个 WHERE 都要有人负责解释」,这句话怎么真的执行下去
附录A 速查与三库差异对照 54 一页纸:语法速查 + SQLite / Postgres / MySQL 差在哪

⚠️ 上表的分钟数是个参考;以各章页首那个 ⏱ 徽章为准,那个是按正文长度算出来的。

⭐ 01–05 是承重墙,后面每一章都踩在它们上面。06 之后的每一章都是独立能力,可以按需要挑。


🧭 三、四条读法路线

⭐ 别从头读到尾,除非你就是想系统学一遍。按你手上要做的事挑:

你要做的事 读哪几章 大概多久
看懂别人写的 SQL(review、接手祖传报表) 01 → 02 → 03 → 04 → 05 → 06 约 9.4 小时(有 🛑 断点,分次读)
自己查数、自己审一份数据 01 → 03 → 04 → 07 → 10 约 7.9 小时
后端写接口 / 查询慢了要救火 01 → 02 → 04 → 05 → 09 约 7.4 小时
做数据、做特征、做看板 03 → 06 → 07 → 08 → 10 约 8.3 小时

⭐ 不管走哪条,01 和 04 都建议不要跳。 01 是全部语法的骨架,04 是全部「不报错的错」的源头 —— 后面每一章至少会回扣它们一次。

⚠️ 如果你从来没写过 SQL:先花 20 分钟在任何一个在线练习站上把 SELECT / WHERE / ORDER BY 敲熟, 再回来从 01 开始。这套教程默认你见过 SQL 长什么样,不默认你会写。


🧰 四、怎么把每段代码跑起来

⭐ 本教程每一段代码都可以复制进一个空文件直接跑,不需要装数据库。

因为 Python 自带 sqlite3。整个教程用的都是内存库:进程结束就没了,跑一百遍也不留垃圾。

import sqlite3

db = sqlite3.connect(":memory:")          # ⭐ 不装任何东西,库就在内存里
db.execute("CREATE TABLE calls(user_id TEXT, feature TEXT, cents REAL)")
db.executemany("INSERT INTO calls VALUES(?,?,?)",
               [("u1", "chat", 0.056), ("u1", "summary", 2.64), ("u2", "summary", 10.2)])

for row in db.execute("SELECT feature, SUM(cents) FROM calls GROUP BY feature"):
    print(row)

print("sqlite 版本:", sqlite3.sqlite_version)

实跑输出:

('chat', 0.056)
('summary', 12.84)
sqlite 版本: 3.50.4

本教程所有实测都跑在 Windows 11 · Python 3.13.14 · SQLite 3.50.4(Python 自带那个)上。

⭐ 为什么选 SQLite 而不是 Postgres: 装一个 Postgres 是运维,而运维不是这套教程的题目。 SQL 的语义 —— 执行顺序、连接、三值逻辑、聚合、窗口 —— 三个库高度一致, 分歧集中在函数名和少数语法糖上。真有分歧的地方,本教程会当场标出来。

⚠️ 两个标记,看到就知道该怎么办:

标记 含义
实跑输出 下面那段文本是从终端抄回来的,不是我写的。你在同版本上跑应该一模一样
🗓️ 未实跑 —— sqlite 无此语法 这是 Postgres / MySQL 特有的写法,本机跑不了,只给形状不给输出

⚠️ 耗时类的数字(毫秒、秒)会随机器变。 凡是出现耗时,正文一定会写明数据规模, 并且要看的是量级差异不是绝对值 —— 你的绝对数值会不同,但量级差异是结构性的。

三个库的完整差异对照在 附录A,遇到分歧再翻。


📐 五、这套教程的三条写作约定

① 每段代码自带建表。 不会出现「接着上一段」。你从任何一节的任何一个代码块开始复制,都能跑。 代价是同一张 calls 表可能建了七八遍 —— 这是故意的。

② 输出是抄回来的,不是想出来的。 包括那些「看起来很怪」的输出(NOT IN 返回空集、AVG 跳过 NULL、COUNT(DISTINCT) 不数 NULL)。 ⭐ 它们怪,正是这套教程存在的理由。

③ 每一章的坑都有一个「不报错」标签。 本教程标了 ⚠️ 的地方,绝大多数都不会给你一个报错。报错是幸运的,报错说明你当场就知道了。 真正贵的是那些跑得好好的、结果错了的。

⭐ 一句话记住整套教程的目标: 让你在按下回车之前,就知道这条查询会返回几行、每行代表什么、以及哪些行被悄悄扔掉了。


🔗 这一章连到哪里

相关的地方 为什么
AI 全栈 · 06 关系数据库 ⭐ 索引怎么建、表怎么设计、迁移怎么做全在那边。本教程 09 章会用它建好的索引,但只讲写法怎么把索引废掉
AI 全栈 · 06b 列表接口与分页 那边 own 游标分页怎么用、COUNT(*) 的成本、SQL 注入;本教程 05 章只回答那个复合游标是什么
AI 全栈 · 12 限流配额与成本护栏 03 章的看板用的也是那一章第六节那张 calls 计费表的思路 —— ⚠️ 字段做了教学裁剪(保留 user_id/feature/model/cents/ms,加了 ok/dt,省去 trace_id/token 数),口径以那边为准
数据这一关 · 04 脏数据的十种形态 数据进模型之前的那一半。本教程假定数据已经在库里,坏在哪是它的题目
模型上线之后 · 04 训练推理一致性 训练侧和线上侧算出两个数的七种形态;本教程 08 章会碰到其中一条的 SQL 侧

✅ 检查点

  1. 这套教程不讲哪四类事?各归站内哪一章?
  2. 判断「一个问题在不在本教程范围内」的那条判据是什么?
  3. 为什么说本教程要拆的错误有一个共同形状?那个形状是什么?
  4. 12 章里哪几章被称作「承重墙」?为什么建议不跳 01 和 04?
  5. 为什么用 SQLite 而不是 Postgres?这个选择的代价是什么、怎么兜底?
  6. 看到 🗓️ 这个标记意味着什么?看到「实跑输出」四个字意味着什么?
  7. 为什么每段代码都要自带建表,哪怕同一张表要建七八遍?
  8. 遇到耗时类的数字(毫秒、秒)该怎么看?
👀 答案
  1. 索引怎么建 → 《AI 全栈》06;COUNT(*) 成本 / 游标分页怎么用 / SQL 注入 → 《AI 全栈》06b; 训推不一致的七种形态 → 《模型上线之后》04;数据本身脏在哪 → 《数据这一关》04。
  2. 看答案的形状:答案是「改表结构」或「加台机器」→ 不在这里;答案是「把这条查询换个写法」→ 在这里。
  3. 不报错。查询跑完了、返回了一张漂亮的表、数字是错的,没有任何一行日志告诉你。 报错是幸运的(当场就知道了),贵的是跑得好好的那种。
  4. 01–05 是承重墙。01 是全部语法的骨架(执行顺序),04 是全部「不报错的错」的源头(三值逻辑), 后面每章至少回扣它们一次。
  5. 因为装一个 Postgres 是运维,而运维不是本教程的题目;Python 自带 sqlite3,:memory: 零安装。 代价是函数名和少数语法糖有分歧(语义 —— 执行顺序 / 连接 / 三值逻辑 / 聚合 / 窗口 —— 三库高度一致), 兜底办法是分歧处当场标 🗓️,完整对照在附录A。
  6. 🗓️ = 这是 Postgres / MySQL 特有语法,本机跑不了,只给形状不给输出; 「实跑输出」= 下面那段文本是从终端抄回来的,同版本(Python 3.13.14 / SQLite 3.50.4)应该一模一样。
  7. 为了从任何一节的任何一个代码块开始复制都能跑,不会出现「接着上一段」。重复建表是故意的。
  8. 看量级差异,不看绝对值 —— 耗时随机器变。正文出现耗时时一定会写明数据规模。

🛑 可以停在这里

⚡ 走神救援

「学 SQL」底下塞了两件事:数据库怎么运起来(表设计、索引、事务、备份、扩容——一年做不了几次)和怎么把一个问题写成查询(每天做十次)。⭐ 这套只做后者,判据是看答案的形状:答案是「改表结构」或「加机器」就不在这里,答案是「把这条查询换个写法」就在这里。

⭐⭐ 它值得单独学,是因为这一侧最贵的错误有个共同形状——不报错:查询跑完了、表也漂亮、数字是错的,没有一行日志提醒你。

站内已经有人 own 的四块一个字不重讲:索引怎么建、COUNT(*) 的成本与游标分页与注入、训推不一致的七种形态、数据本身脏在哪。⭐ 而接缝是双向的:这边讲「写法怎么把已经建好的索引废掉」,那边讲「索引怎么建」;这边回答那个复合游标条件是什么,那边 own 怎么用。

⭐ 01–05 是承重墙,06 之后每章是独立能力可以挑着读。四条路线按目的分(看懂别人的 SQL / 自己查数审数据 / 后端写接口救火 / 做数据看板),⭐ 不管走哪条,01 和 04 都别跳。

跑代码不用装数据库:Python 自带的 sqlite3 三行起步。⭐ 选它是因为装 Postgres 本身就是运维,而 SQL 的语义(执行顺序、连接、三值逻辑、聚合、窗口)三个库高度一致,分歧集中在函数名和语法糖上——分歧处当场标 🗓️「未实跑,本机无此语法」。

三条写作约定:每段代码自带建表(能从任何一块开始复制,⭐ 重复建表是故意的)、输出是从终端抄回来的(包括那些看起来很怪的),⚠️ 耗时类数字随机器变,看量级不看绝对值。

下一节 👉 01-一条查询是怎么跑的.md

打卡记录保存在你的浏览器里,首页能看到总进度