SQL 课程指南

← 首页
📖 课程指南
🏠 首页 🎯 综合练习 📚 学习材料 ✏️ 练习 🧠 测验
第 1 课 / 共 4 课
🗄️ SQL 与数据库入门
什么是 SQL、它为何重要、数据库长什么样,以及 SQL 与 Excel 的区别。
SQL 数据库 主键 外键 Northwind
🔍 什么是 SQL?
定义
SQL = 结构化查询语言 —— 一种结构化查询语言。

不像 Python 或 Java 这类“通用语言”,SQL 是一种 领域专用语言 专门为处理数据而设计。

SQL 的语法类似于 近乎自然的英语 —— 像 SELECT, FROM, WHERE 这样的命令让代码可读又清晰。
📜
历史: SQL 于 20 世纪 70 年代在 IBM 实验室开发,最初名为 SEQUEL。从那以后它一直是数据领域的主导语言——已超过 50 年!
❓ 为什么要用 SQL,而不是 Excel?
3 个主要原因
1. 大数据 —— 海量信息
当 Excel 开始“卡顿”(大约一百万行)时——SQL 才刚刚热身。SQL 在几秒内就能处理数十亿行。

2. “单一可信数据源” —— 一个中央数据库
与在邮件里到处流传、不断变化的文件不同,SQL 维护一个中央数据库,防止错误,并保持逻辑关系完整。

3. 精准检索
Excel 把整个文件加载到内存中。SQL 检索 你需要的特定数据——节省内存并缩短运行时间。
对比项ExcelSQL
行数最多约 100 万行数十亿行
速度处理大文件时慢非常快
数据共享文件到处传递一个中央数据库
安全性任何人都能编辑权限与控制
执行计算对普通用户方便强大而精确
🗃️ 数据库长什么样?
数据库结构
数据库由 组成。每张表包含 .

想象几个相互关联的 Excel 工作表——这就是数据库的样子。
1
数据库 —— 整个数据库(例如 Northwind)
2
—— 数据库中的表(例如 customers、orders、products)
3
—— 表中的列(例如 id、first_name、city)
4
—— 数据行(例如某个具体客户的详细信息)
🔑 键与关系
主键
一个能 唯一 标识每一行的列。任何两个值都不能相同。它不能为 NULL。
示例: id 列(在 customers 表中)—— 每个客户都有自己唯一的编号。
外键
一个表中的列,指向 另一个表中的主键。它在两个表之间建立关系。
示例: customer_id 列(在 orders 表中)指向 customers 表中的 id
💡
提示: 主键与外键之间的关系是 JOIN 命令的基础——你就是这样把来自不同表的信息组合起来的。
🏪 课程数据库 —— Northwind
什么是 Northwind?
一个经典的数据库,模拟一家 贸易公司。它包含客户、订单、产品、供应商和员工。数十年来被广泛用于教授 SQL。
主要的表
customers —— 客户 | orders —— 订单 | order_details —— 订单行项目
products —— 产品 | employees —— 员工 | suppliers —— 供应商 | shippers —— 物流公司
第 2 课 / 共 4 课
📝 字符串函数
清理、提取、格式化和标准化文本数据。4 大类操作。
UPPER / LOWER LEFT / RIGHT SUBSTRING TRIM / REPLACE LENGTH CONCAT
🧹 第 1 类:清理数据
TRIM / LTRIM / RTRIM
去除字符串中多余的空格。
TRIM —— 两侧 | LTRIM —— 仅左侧 | RTRIM —— 仅右侧
SQL
SELECT TRIM('   hello world   ') AS clean_text;
-- 结果:'hello world'

SELECT company, TRIM(company) AS clean_company
FROM customers;
REPLACE
用另一个子串替换某个子串。
REPLACE(列, '要替换的内容', '替换成的内容')
SQL
-- 移除电话号码中的短横线
SELECT REPLACE(business_phone, '-', '') AS clean_phone
FROM customers;

-- 把 UK 替换为 United Kingdom
SELECT REPLACE(country_region, 'UK', 'United Kingdom')
FROM customers;
✂️ 第 2 类:提取数据
LEFT / RIGHT
LEFT(列, N) —— 从开头数 N 个字符
RIGHT(列, N) —— 从结尾数 N 个字符
SQL
-- 公司名称的前 3 个字母
SELECT company, LEFT(company, 3) AS short_code
FROM customers;

-- 电话的后 4 位
SELECT RIGHT(business_phone, 4) AS phone_end
FROM customers;
SUBSTRING
SUBSTRING(列, 起始, 长度) —— 从指定位置提取。
Important: 位置从 1 开始(不是 0!)。
SQL
-- 从第 2 个字符开始的 5 个字符
SELECT SUBSTRING(product_name, 2, 5) AS middle_text
FROM products;
LENGTH 和 INSTR
LENGTH(column) —— 返回字符串的字符长度
INSTR(列, '字符') —— 返回子串的位置
SQL
SELECT email_address,
       LENGTH(email_address) AS email_length,
       INSTR(email_address, '@') AS at_position
FROM employees;
🎨 第 3 类:重新格式化
CONCAT 和 CONCAT_WS
CONCAT(a, b, c) —— 连接字符串。如果任一值为 NULL——结果就是 NULL。
CONCAT_WS(分隔符, a, b, c) —— 用固定的分隔符连接 并自动跳过 NULL.
SQL
-- 用逗号连接的完整地址(跳过 NULL)
SELECT CONCAT_WS(', ', city, state_province, zip_postal_code) AS full_address
FROM customers;

-- 带 $ 符号的价格
SELECT CONCAT('$', ROUND(list_price, 2)) AS formatted_price
FROM products;
✅ 第 4 类:标准化与一致性
UPPER / LOWER
UPPER(column) —— 将所有文本转换为大写
LOWER(column) —— 将所有文本转换为小写

在比较前规范化数据时很有用。
SQL
SELECT UPPER(company) AS company_caps
FROM suppliers;

SELECT LOWER(email_address) AS standard_email
FROM employees;
⚠️
Note: UPPER/LOWER 只改变 显示效果 —— 它们不会把更改保存到表中。要永久更改需要使用 UPDATE。
第 3 课 / 共 4 课
🔎 WHERE —— 筛选数据
按条件筛选行。真实查询中最核心的工具——包括 AND/OR、IN、BETWEEN、LIKE 和 IS NULL。
WHERE AND / OR IN BETWEEN LIKE IS NULL
📍 基本 WHERE
Syntax
WHERE 位于 FROM 之后 并按条件筛选行。
比较运算符: = != < > <= >=
SQL
-- 价格超过 50 的产品
SELECT product_name, list_price
FROM products
WHERE list_price > 50;

-- 不是销售代表的员工
SELECT first_name, job_title
FROM employees
WHERE job_title != 'Sales Representative';
🔗 AND / OR —— 多个条件
区别
AND两个 条件都必须成立
OR至少满足一个 of the 条件都必须成立

括号设定优先级: WHERE (a OR b) AND c
SQL
-- AND:来自美国和纽约的客户
SELECT * FROM customers
WHERE country_region = 'USA'
  AND city = 'New York';

-- OR:来自 Beverages 或 Condiments 类别的产品
SELECT product_name FROM products
WHERE category = 'Beverages'
   OR category = 'Condiments';
📋 IN —— 一组值
什么是 IN?
IN 是多个 OR 的便捷简写。更易读也更简短。
WHERE city IN ('Tel Aviv', 'Jerusalem', 'Haifa')
SQL
-- 来自 3 个城市的供应商(OR 的简写)
SELECT company, city
FROM suppliers
WHERE city IN ('Tokyo', 'London', 'New York');

-- NOT IN:不来自这些城市
SELECT * FROM customers
WHERE country_region NOT IN ('USA', 'UK');
📏 BETWEEN —— 一段值的范围
需要知道
BETWEEN x AND y —— 包含两个端点(x 和 y 本身)。
等价于: WHERE col >= x AND col <= y
SQL
-- 运费在 20 到 50 之间的订单
SELECT id, shipping_fee
FROM orders
WHERE shipping_fee BETWEEN 20 AND 50;
🔍 LIKE —— 模式搜索
通配符
% —— 任意数量的字符(包括零个)
_ —— 恰好一个字符

'%gmail%' —— 包含 gmail | 'j%' —— 以 j 开头 | '%@gmail.com' —— 以 @gmail.com 结尾
SQL
-- 以 northwindtraders.com 结尾的邮箱
SELECT * FROM employees
WHERE email_address LIKE '%northwindtraders.com';

-- 以 A 开头的名字
SELECT first_name FROM employees
WHERE first_name LIKE 'A%';
🚫 IS NULL / IS NOT NULL
NULL —— 缺失的值
NULL 是一个 缺失 / 未知的 值——不是零,也不是空!
你不能使用 = NULL —— 你必须使用 IS NULL.
SQL
-- 尚未发货的订单
SELECT id, order_date
FROM orders
WHERE shipped_date IS NULL;

-- 有网站的客户
SELECT company, web_page
FROM customers
WHERE web_page IS NOT NULL;
常见错误! WHERE shipped_date = NULL —— 这 行不通 在 SQL 中!始终使用 IS NULL.
第 4 课 / 共 4 课
📦 GROUP BY 与聚合
对行分组并计算统计值——COUNT、SUM、AVG、MIN、MAX。包含 HAVING、ROLLUP 和 UNION。
GROUP BY COUNT SUM / AVG MIN / MAX HAVING ROLLUP UNION
📊 聚合函数
主要函数
COUNT(*) —— 统计行数 | COUNT(column) —— 统计非 NULL 的值
SUM(column) —— 计算总和
AVG(column) —— 计算平均值
MIN(column) —— 最小值
MAX(column) —— 最大值
SQL
-- products 表的统计信息
SELECT
  COUNT(*) AS total_products,
  AVG(list_price) AS avg_price,
  MIN(list_price) AS min_price,
  MAX(list_price) AS max_price
FROM products;
🗂️ GROUP BY —— 分组
重要规则
SELECT 中每个不是聚合函数的列 必须 出现在 GROUP BY 中。
GROUP BY 把表拆分成若干组,并为每组计算一个聚合值。
SQL
-- 每个类别中有多少个产品?
SELECT category, COUNT(*) AS product_count
FROM products
GROUP BY category;

-- 每个类别的平均价格
SELECT category, AVG(list_price) AS avg_price
FROM products
GROUP BY category
ORDER BY avg_price DESC;
🔍 HAVING —— 分组后筛选
WHERE 与 HAVING
WHERE —— 筛选行 before grouping
HAVING —— 筛选组 after grouping

Rule: 你不能在 WHERE 中使用聚合函数(COUNT、SUM……)——这就是需要 HAVING 的原因。
SQL
-- 产品超过 5 个的类别
SELECT category, COUNT(*) AS cnt
FROM products
GROUP BY category
HAVING COUNT(*) > 5;

-- WHERE(之前)+ HAVING(之后)
SELECT category, AVG(list_price) AS avg
FROM products
WHERE list_price > 10        -- 分组前筛选
GROUP BY category
HAVING AVG(list_price) > 30; -- 分组后筛选
💡
记忆技巧: WHERE → 在 GROUP BY 之前(作用于行)。HAVING → 在 GROUP BY 之后(作用于组)。
📈 ROLLUP —— 总计
什么是 ROLLUP?
GROUP BY column WITH ROLLUP —— 在结果末尾添加一行总计汇总。
最后一行在分组列中为 NULL,并包含总计。
SQL
-- 按类别计数 + 总计
SELECT
  COALESCE(category, '--- TOTAL ---') AS category,
  COUNT(*) AS total
FROM products
GROUP BY category WITH ROLLUP;
🔀 UNION —— 合并结果
UNION 与 UNION ALL
UNION —— 合并两个查询的结果并去除重复
UNION ALL —— 合并并保留重复(更快)

Requirement: 两个查询必须返回相同数量的列,且数据类型兼容。
SQL
-- 来自 customers 和 suppliers 的城市合并列表
SELECT city, 'customer' AS type FROM customers
UNION
SELECT city, 'supplier' AS type FROM suppliers
ORDER BY city;
📋 SQL 执行顺序 —— 很重要!
1
FROM —— 从哪张表读取
2
WHERE —— 筛选行
3
GROUP BY —— 分组
4
HAVING —— 筛选组
5
SELECT —— 选择要显示的列
6
ORDER BY —— 对结果排序
7
LIMIT —— 限制行数
💡
我们 编写 SQL 的顺序,不同于数据库 执行 它的顺序。这就是为什么你不能在 WHERE 中使用 SELECT 的别名。