如果你不明确写 ORDER BY,数据库系统绝对不保证返回结果的顺序。把它当成“完全随机”来对待是最安全的做法。
SQL 是一种结构化查询语言(Structured Query Language),专门用来与数据库打交道,目的是提供一种从数据库中读写数据的简单有效的方法。
DDL:#
数据定义语言(Data Definition Language)用于数据模式定义、规定一致性约束、为用户授权等。常
核心命令:CREATE、ALTER、DROP
truncate (清空数据) 和 delete (是DML语句)只删除数据不删除表的结构(定义),执行 drop 语句,此表的结构也会删除
mysql字段类型#

char 和 varchar#
约束#
SQL 约束用于规定表中的数据规则
NOT NULL- 指示某列不能存储 NULL 值。UNIQUE- 保证某列的每行必须有唯一的值。PRIMARY KEY- NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。FOREIGN KEY- 保证一个表中的数据匹配另一个表中的值的参照完整性。
AUTO_INCREMENT 不仅仅修饰主键(最常见场景),但必须修饰某个有索引的整数列
DML!数据操纵语言#
数据库数据的增删改查
核心命令:INSERT、UPDATE、DELETE、SELECT,合称 CRUD
INSERT into 表名 values (元组) 也可以插入部分列,其他列会被填充为默认值
UPDATE 表名 SET 列/属性 WHERE
DELETE FROM 表名
DQL:#
SELECT DISTINCT:返回唯一不同的值.作用于所有列,也就是说所有列的值都相同才算相同
LIMIT 限制返回的行数。可以有两个参数,第一个参数为起始行,从 0 开始;第二个参数为返回的总行数。
条件#
where and having 都是条件
执行顺序 where>聚合>having 分组之后查询的字段通常为聚合函数和分组字段 其他字段无意义
范围#
IN 和 BETWEEN(闭区间)
字段须是文本值 LIKE。 % 表示任何字符出现任意次数。_ 表示任何字符出现一次。
分组#
having一般都是和group by连用,用于对汇总的group by结果进行过滤。
在 SELECT 列表里,除了聚合字段,剩下的所有普通字段,一个不落,全都要写进 GROUP BY 后面
排序#
order by 对多列排序的时候,先排序的列放前面,后排序的列放后面并且,不同的列可以有不同的排序规则。
DCL#
管理用户
控制权限GRANT 和 REVOKE
-- 创建⻆⾊并授权
CREATE ROLE 'clerk';
GRANT SELECT, INSERT, UPDATE ON course TO 'clerk';
-- 创建⽤户并赋予⻆⾊
CREATE USER 'user01'@'localhost' IDENTIFIED BY '123456';
GRANT 'clerk' TO 'user01'@'localhost';
SET DEFAULT ROLE 'clerk' TO 'user01'@'localhost';
-- 收回对 course 表的更新权限
REVOKE UPDATE ON course FROM 'clerk';sql函数#
SQL提供5个聚集函数 max min avg sum count
字符串 TRIM()
数值函数 RAND()返回0~1
日期函数
汇总函数
COUNT(列名):统计某一列中非 NULL 值的行数。
COUNT(常量):就等价于 COUNT(*)统计所有行数。
DISTINCT 可以让汇总函数值汇总不同的值
控制流程函数
IF(条件表达式, 值_if_true, 值_if_false)
FROM (...) 得到的是一个临时结果集(派生表) 派生表必须有别名
CASE WHEN 条件1 THEN 结果1 [WHEN 条件2 THEN 结果2 ...] [ELSE 默认结果] END
动态升序/降序 如果想让男性的 GPA 升序,女性的 GPA 降序:
SELECT name, gender,gpa
FROM users
ORDER BY
CASE gender
WHEN 'male' THEN gpa
ELSE -gpa -- 负值实现降序
END;plaintextcase when 子句中,遇到null值会进入下一个判断条件
窗口函数 排序类
row_number():每行一个唯一递增编号(1,2,3…)rank():相同值并列,后面跳号dense_rank():相同值并列,但不跳号 窗口函数名(…) over (partition by 分组字段 order by 排序字段)
表关系 / 连接关系#
一对多 不推荐用外键约束 使用逻辑外键 一对一关系表 就是大表拆分成小表. 在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE) 多对多 :需要建立一张中间表,中间表中有两个外键字段,分别关联两方的主键。
多表查询#
SQL 先根据 ON 生成一张临时表,然后再根据 WHERE 对临时表进行筛选
直接查询的结果是两张表的笛卡尔积

子查询#
用小扩号嵌套select 根据子查询结果的不同分为:
- 标量子查询(子查询结果为单个值)
- 列子查询(子查询结果为一列,但可以是多行)
INANY - 行子查询(子查询结果为一行,但可以是多列)
- 表子查询(子查询结果相当于子查询结果是一张表)结果作为临时表联查 ,嵌套越多性能越低
尽量用 JOIN来代替子查询,因为 JOIN 往往能更好地利用索引。
相关子查询#
作用:集合判断
EXISTS vs IN 的本质区别
IN关心的是“值”:子查询必须明确SELECT出具体的字段(比如姓名),用来给外层做比对。EXISTS关心的是“有没有”:子查询SELECT什么根本不重要(所以我们通常写SELECT 1),它只关心能不能查到行数。要想让它准确判断某一个人的情况,就必须用WHERE把内外层表关联起来(也就是上一题跟你讲的“内外桥梁”)。
所以,记住这个铁律: 用 EXISTS,子查询里必有 WHERE 关联外层表;如果子查询没写关联条件,那 99% 是写出 Bug 了!
WITH 子句(CTE)#
CTE 的本质,就是给一个复杂的子查询结果集“起个名字”,把它变成当前 SQL 语句生命周期内的一个“临时表”。 可以理解为局部变量 基础语法结构:
WITH
-- 定义第一个 CTE
cte_name_1 AS (
SELECT ... FROM ...
),
-- 定义第二个 CTE,甚至可以引用第一个 CTE
cte_name_2 AS (
SELECT ... FROM cte_name_1 WHERE ...
)
-- 最终的主查询
SELECT * FROM cte_name_2;plaintext连接查询!#

默认是内连接 INNER JOIN :#
相当于查询A、B交集部分数据 用逗号分隔两张表(使用where是隐式内连接)
外连接#
- 左外连接:查询左表所有数据(包括交集)
select 字段列表 from 表1 left [outer] join 表2 on 连接条件 ... ;plaintext显然左右可以相互转换
ON:是生成临时大表时的连接条件。在 LEFT JOIN 中,即使 ON 后面的条件不成立,左表的数据依然会保留(右表补 NULL)。
WHERE:是对已经生成好的临时大表进行最终过滤。如果不满足 WHERE 条件,这条数据就会被彻底踢出结果集。
SQL 先根据 ON 生成一张临时表,然后再根据 WHERE 对临时表进行筛选
- 自连接 可以是内也可是外连接 必须起别名
假设我们在开发一个电商系统,有两个基础表:用户表(User 表 A,在左边) 和 订单表(Order 表 B,在右边)
-
INNER JOIN(内连接):
A ∩ B- 效果: 只查询出“下过订单的用户”及其“对应的订单”。没有下过单的用户,以及由于脏数据导致找不到对应用户的订单,统统不显示。
-
LEFT JOIN(左外连接):
A ∪ (A ∩ B)- 效果: 以左表(用户表 A)为基准。查出系统里的所有用户。如果这个用户下过单,就把订单信息拼接在后面;如果这个用户是个新注册的“白嫖党”,从来没下过单,那么查询结果里该用户的订单字段全部显示为
NULL。
- 效果: 以左表(用户表 A)为基准。查出系统里的所有用户。如果这个用户下过单,就把订单信息拼接在后面;如果这个用户是个新注册的“白嫖党”,从来没下过单,那么查询结果里该用户的订单字段全部显示为
-
RIGHT JOIN(右外连接):
B ∪ (A ∩ B)- 效果: 以右表(订单表 B)为基准。查出系统里的所有订单。正常情况下订单都有对应的用户,如果因为系统 Bug 导致某个订单失去了用户 ID,这条订单依然会被查出来,只不过它的用户信息部分是
NULL。
- 效果: 以右表(订单表 B)为基准。查出系统里的所有订单。正常情况下订单都有对应的用户,如果因为系统 Bug 导致某个订单失去了用户 ID,这条订单依然会被查出来,只不过它的用户信息部分是
组合/集合运算#
UNION 运算符将多个查询结果集合并为一个结果集。
UNION 基本规则:
- 所有查询的列数和列顺序必须相同。
- 每个查询中涉及表的列的数据类型必须相同或兼容。
- 通常返回的列名取自第一个查询。
保留重复值使用 UNION ALL。
where+or 会条件短路导致重叠行只出现一次
并集(union)、交集(intersect)、差集(except)是去重的。 保留重复必须用 all 。即 union all 、 intersect all 、 except all