第 1 课 / 共 4 课
🗄️ SQL 与数据库入门
什么是 SQL、它为何重要、数据库长什么样,以及 SQL 与 Excel 的区别。
🔍 什么是 SQL?
定义
SQL = 结构化查询语言 —— 一种结构化查询语言。
不像 Python 或 Java 这类“通用语言”,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 检索 仅 你需要的特定数据——节省内存并缩短运行时间。
当 Excel 开始“卡顿”(大约一百万行)时——SQL 才刚刚热身。SQL 在几秒内就能处理数十亿行。
2. “单一可信数据源” —— 一个中央数据库
与在邮件里到处流传、不断变化的文件不同,SQL 维护一个中央数据库,防止错误,并保持逻辑关系完整。
3. 精准检索
Excel 把整个文件加载到内存中。SQL 检索 仅 你需要的特定数据——节省内存并缩短运行时间。
| 对比项 | Excel | SQL |
|---|---|---|
| 行数 | 最多约 100 万行 | 数十亿行 |
| 速度 | 处理大文件时慢 | 非常快 |
| 数据共享 | 文件到处传递 | 一个中央数据库 |
| 安全性 | 任何人都能编辑 | 权限与控制 |
| 执行计算 | 对普通用户方便 | 强大而精确 |
🗃️ 数据库长什么样?
数据库结构
数据库由 表组成。每张表包含 列 和 行.
想象几个相互关联的 Excel 工作表——这就是数据库的样子。
想象几个相互关联的 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 大类操作。
🧹 第 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
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。
📊 聚合函数
主要函数
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 把表拆分成若干组,并为每组计算一个聚合值。
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 groupingHAVING —— 筛选组 after groupingRule: 你不能在 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 的别名。