跳到正文
本地阅读 · 数据库、表与基本查询

数据库、表与基本查询

计算机基础 · SQL
本章目录

本章学习目标

  • 区分数据库、表、行与列
  • 写出确定排序的投影与过滤查询
  • 建立主键、粒度和数据字典意识
前置知识:无需前置章节

从业务对象到关系表

数据库是若干相关表的集合,表描述一种业务对象或事件。users 记录注册用户,orders 记录订单,order_items 记录订单商品,events 记录行为,assignments 记录实验分配。把这些对象全部塞进一张宽表,会反复复制用户属性并混淆事件与订单的粒度;分表后通过键关联,既能明确每行含义,又能减少重复维护。

主键唯一标识一行,它与展示顺序没有关系。订单编号不能被当成订单日期,也不保证编号连续。user_id 是整数标识,amount 是定点金额,order_date 是包含时间的日期时间。列类型决定比较和运算方式;把金额作为文本会使排序按字符顺序进行,把日期作为任意字符串会使日期函数失去清晰含义。先读数据字典,再写查询。

SELECT、FROM、WHERE 的基本职责

FROM 指定来源,WHERE 选择符合条件的行,SELECT 决定输出哪些列。查询订单编号、时间和金额时,结果仍是一笔订单一行,只是减少了列。WHERE amount >= 100 对每一行判断,满足条件才保留;SELECT 中的 amount-refund_amount AS net_amount 是派生列,原表不会被修改。

示例先显示当前数据库,再查看表结构,最后查询支付过的订单。paid 与 refunded 都属于已支付,取消订单不计入。净收入是金额减退款;这是一项明确的课程口径,并不是所有公司的统一定义。拿到实际岗位的数据,要先确认税费、运费、退款发生时间等边界。查询本身只读取,不能因为出现计算表达式就认为数据库数据被更新。

顺序、限制行数与可复核结果

关系表没有承诺默认行序。ORDER BY order_date,order_id 先按时间再按唯一编号排序,同一时间的订单也有稳定次序。LIMIT 5 表示从排序后的结果取五行;未排序就限制行数只适合粗略预览,不能叫最早五笔或最高五笔。降序使用 DESC,升序可以写 ASC;多个排序列可采用不同方向。

SELECT * 有利于初次探索,却不适合作为稳定接口:新增列会改变输出结构,多表连接还可能产生同名列。正式示例明确选择所需列并给计算列起名。DISTINCT 在所选列组合上去重,SELECT DISTINCT country,channel 得到国家与渠道组合,而不是分别去重两列。想数原始行数不要先随意 DISTINCT,否则重复数据问题可能被隐藏。

第一次运行及错误定位

在 MySQL 客户端中选择 data_skills_course,再运行本章脚本。SHOW COLUMNS 帮助确认列名,SELECT DATABASE() 帮助确认连接了正确数据库。若表不存在,先检查初始化是否完成;若列不存在,检查拼写与表别名;如果查询返回零行,应检查筛选条件和数据范围,而不是直接删除 WHERE。

MySQL 字符串通常用单引号,保留字或特殊标识符可用反引号。SQL 子句顺序不同于某些数据处理 API 的链式顺序,SELECT 别名一般不能在同级 WHERE 使用,因为筛选时该派生值尚未形成。可以重复表达式,或在后续章节用子查询、CTE 提供中间结果。学习初期每次只添加一个条件,并解释它改变了多少行。

从结果到验证

阅读一段查询时,先写下一行结果代表什么,再列出来源表的一行代表什么。把过滤、连接、聚合和排序分别检查,比仅凭输出看起来合理更可靠。对于金额应同时保留订单数量和用户数量,以便发现连接引起的重复累计;对于比率应同时展示分子与分母,以便发现筛选范围不同。结果少并不等于正确,结果多也不等于错误,判断依据是预先确定的业务口径。

先用纸笔构造三个用户、两三个订单的小表,再用数据库运行对应查询。至少包含没有订单的用户、同一用户多笔订单、一个未知值,以及筛选后没有记录的情形。用这些反例解释每个子句造成的变化,再扩大到课程数据。未写 ORDER BY 的结果没有稳定顺序;需要核对输出时总要明确排序。课程默认 MySQL 8.4,开启严格分组规则,不要通过关闭规则掩盖数据粒度问题。

完成练习后,先自行解释结果再查看答案。记录的检查标准应是行数、键是否唯一、是否有空值、金额是否守恒,以及日期边界是否符合定义,而不只是查询没有语法错误。答案中的每个条件都应能追溯到题目口径;如果口径改变,先调整定义再改查询。这样形成的推理过程可以直接用于面试中解释思路和实际工作中复核分析报告。

完整示例与实际输出

SELECT DATABASE() AS current_database;
SHOW COLUMNS FROM orders;
SELECT order_id,user_id,order_date,amount,refund_amount,
       amount-refund_amount AS net_amount
FROM orders WHERE status IN ('paid','refunded')
ORDER BY order_date,order_id LIMIT 5;
SELECT DISTINCT country,channel FROM users ORDER BY country,channel;

实际运行通过Actual MySQL 8.4.11 execution; strict grouping mode.

current_database
data_skills_course

Field	Type	Null	Key	Default	Extra
order_id	int	NO	PRI	NULL	
user_id	int	YES		NULL	
order_date	datetime	NO		NULL	
status	varchar(16)	YES		NULL	
amount	decimal(10,2)	YES		NULL	
refund_amount	decimal(10,2)	YES		NULL	

order_id	user_id	order_date	amount	refund_amount	net_amount
50	2	2026-01-01 02:00:00	240.00	0.00	240.00
1	1	2026-01-02 01:00:00	48.00	0.00	48.00
2	2	2026-01-03 02:00:00	240.00	0.00	240.00
51	3	2026-01-03 03:00:00	12.50	0.00	12.50
30	6	2026-01-03 06:00:00	12.50	0.00	12.50

country	channel
CN	organic
SG	referral
US	ads

五道自测:先回答,再核对

01 · orders 一行表示什么?

查看提示

先读表的粒度。

查看参考答案

一笔订单,order_id 唯一;不能把一行当成一个用户或一个商品。

02 · SELECT 中计算净额会修改原表吗?

查看提示

区分查询与写入。

查看参考答案

不会,SELECT 返回派生结果;修改数据需要 UPDATE 等写入语句。

03 · LIMIT 5 就是最早五笔吗?

查看提示

检查有无时间排序。

查看参考答案

不是;必须 ORDER BY order_date,order_id 后 LIMIT 5 才定义最早和并列顺序。

04 · DISTINCT country,channel 去重什么?

查看提示

将两列看成一对。

查看参考答案

对国家和渠道的组合去重,而不是独立去重后随意配对。

05 · 为何正式输出不建议 SELECT *?

查看提示

考虑表增加列。

查看参考答案

会扩大输出、造成接口结构变化及同名列歧义;明确列名更容易复核。

两项动手任务

任务 1 · 取订单净额最高的三笔,净额相同按编号升序。

提示

计算列可在 ORDER BY 中引用。

完整参考解答与检查方式SELECT order_id,amount-refund_amount AS net_amount FROM orders WHERE status IN ('paid','refunded') ORDER BY net_amount DESC,order_id ASC LIMIT 3; 这里排除取消订单。

任务 2 · 列出中国注册用户的编号、注册日和渠道,按日期与编号排序。

提示

country 存储的是国家代码。

完整参考解答与检查方式SELECT user_id,signup_date,channel FROM users WHERE country='CN' ORDER BY signup_date,user_id; 先确认课程数据字典以 CN 表示中国。

官方资料与掌握状态

完成两项任务后,按独立完成程度记录。状态会尽量保存在当前浏览器,可导出备份。

动手任务记录

掌握状态与复习

关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。

记录尽量保存在当前浏览器,建议定期导出备份。