SQL 语言全面详解
一、SQL 基础概念
1.1 什么是 SQL
SQL(Structured Query Language,结构化查询语言)是用于管理关系型数据库的标准化编程语言,主要功能包括数据查询、插入、更新、删除及数据库结构定义等。其核心特点:
- 标准化:遵循 ISO 制定的 SQL99 等标准,跨数据库通用(如 MySQL、Oracle、SQL Server)。
- 操作对象:针对数据库、表、记录等进行操作,实现对数据的 CRUD(Create、Read、Update、Delete)。
1.2 SQL 与数据库的关系
- MySQL 是数据库管理软件(RDBMS),而 SQL 是操作 MySQL 的语言。
数据库对象层级关系:
数据库软件(如 MySQL)→ 数据库(Database)→ 数据表(Table)→ 列(Column/字段)→ 行(Row/记录)
1.3 SQL 语言分类
按功能分为四大类:
| 分类 | 全称 | 作用 | 核心操作 |
|---|---|---|---|
| DDL | 数据定义语言 | 定义 / 修改数据库、表等结构 |
CREATE、ALTER、DROP
|
| DML | 数据操作语言 | 操作表中数据(增删改) |
INSERT、UPDATE、DELETE
|
| DQL | 数据查询语言 | 查询表中数据 | SELECT |
| DCL | 数据控制语言 | 管理用户权限和安全 |
GRANT、REVOKE
|
二、DDL(数据定义语言)
用于定义数据库、表、列等结构,不直接操作数据。
2.1 数据库操作
| 操作 | 语法示例 | 说明 |
|---|---|---|
| 查看所有数据库 | SHOW DATABASES; |
显示 MySQL 中所有数据库(含系统库) |
| 创建数据库 |
CREATE DATABASE 库名;CREATE DATABASE IF NOT EXISTS 库名;
|
若库不存在则创建(避免重复报错) |
| 删除数据库 |
DROP DATABASE 库名;DROP DATABASE IF EXISTS 库名;
|
若库存在则删除(谨慎操作,不可恢复) |
| 切换数据库 | USE 库名; |
指定当前操作的数据库(必须先执行) |
| 查看当前数据库 | SELECT DATABASE(); |
显示当前正在操作的数据库 |
2.2 数据表操作
2.2.1 表的创建与查看
| 操作 | 语法示例 | 说明 |
|---|---|---|
| 查看当前库所有表 | SHOW TABLES; |
需先执行 USE 库名;
|
| 创建表 | sql CREATE TABLE 表名( 列名1 数据类型 [约束], 列名2 数据类型 [约束], ... -- 最后一列无逗号 ); |
定义表的字段、类型及约束 |
| 查看表结构 |
DESC 表名; 或 SHOW COLUMNS FROM 表名;
|
显示表的字段名、类型、约束等信息 |
2.2.2 表的修改与删除
| 操作 | 语法示例 | 说明 |
|---|---|---|
| 修改表名 | ALTER TABLE 旧表名 RENAME TO 新表名; |
重命名数据表 |
| 新增列 |
ALTER TABLE 表名 ADD 列名 数据类型 [约束];ALTER TABLE 表名 ADD 列名 类型 AFTER 已有列;
|
在指定位置添加新字段 |
| 删除列 | ALTER TABLE 表名 DROP 列名; |
从表中删除指定字段(数据会丢失) |
| 修改列名 / 类型 | ALTER TABLE 表名 CHANGE 旧列名 新列名 新类型 [约束]; |
同时修改列名和类型 |
| 修改列类型 | ALTER TABLE 表名 MODIFY 列名 新类型 [约束]; |
仅修改列的类型或约束 |
| 删除表 |
DROP TABLE 表名;DROP TABLE IF EXISTS 表名;
|
若表存在则删除(数据和结构全丢失) |
DDL示例:
数据库创建→切换→表创建→表结构查看→表名修改→增列→改列类型→改列名→删列→删表→删库
-- 一、数据库操作
-- 查看所有数据库
SHOW DATABASES;
-- 创建数据库(不存在则创建)
CREATE DATABASE IF NOT EXISTS mydb;
-- 删除数据库(存在则删除)
DROP DATABASE IF EXISTS mydb;
-- 切换数据库
USE mydb;
-- 查看当前数据库
SELECT DATABASE();
-- 二、数据表操作(需先执行 USE mydb;)
-- 2.1 表的创建与查看
-- 创建表(用户表:id主键、姓名、年龄)
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(20),
age INT
);
-- 查看当前库所有表
SHOW TABLES;
-- 查看表结构
DESC user;
SHOW COLUMNS FROM user;
-- 2.2 表的修改与删除
-- 修改表名(user→t_user)
ALTER TABLE user RENAME TO t_user;
-- 新增列(添加性别列,在name后)
ALTER TABLE t_user ADD gender CHAR(1) AFTER name;
-- 删除列(删除age列)
ALTER TABLE t_user DROP age;
-- 修改列名+类型(name→username,长度30)
ALTER TABLE t_user CHANGE name username VARCHAR(30);
-- 仅修改列类型(gender改为VARCHAR(2))
ALTER TABLE t_user MODIFY gender VARCHAR(2);
-- 删除表(存在则删除)
DROP TABLE IF EXISTS t_user;
三、数据类型与约束
3.1 常用数据类型
| 类型分类 | 具体类型 | 说明及示例 |
|---|---|---|
| 数值型 | INT |
整数(默认长度 11,如 id INT) |
DOUBLE(M,D) |
浮点型(M 总长度,D 小数位,如 score DOUBLE(5,2)) |
|
| 字符串型 | CHAR(N) |
定长字符串(不足补空格,如 sex CHAR(1)) |
VARCHAR(N) |
可变长字符串(按实际长度存储,如 name VARCHAR(20)) |
|
| 日期时间型 | DATE |
日期(年 - 月 - 日,如 birthday DATE) |
DATETIME |
日期 + 时间(年 - 月 - 日 时:分: 秒,如 create_time DATETIME) |
3.2 约束(Constraint)
约束用于限制表中数据,保证数据完整性和一致性。
| 约束类型 | 关键字 | 作用 | 示例 |
|---|---|---|---|
| 主键约束 | PRIMARY KEY |
列值非空且唯一(唯一标识记录) | id INT PRIMARY KEY |
| 自增约束 | AUTO_INCREMENT |
配合主键使用,自动递增(避免重复) | id INT PRIMARY KEY AUTO_INCREMENT |
| 唯一约束 | UNIQUE |
列值可空但不可重复(如手机号) | phone VARCHAR(20) UNIQUE |
| 非空约束 | NOT NULL |
列值不可为空(如姓名) | name VARCHAR(20) NOT NULL |
| 默认值约束 | DEFAULT |
未赋值时使用默认值(如性别默认 “男”) | sex CHAR(1) DEFAULT '男' |
| 外键约束 | FOREIGN KEY |
关联多表(子表值需存在于父表主键中) | sql FOREIGN KEY(uid) REFERENCES user(id) |
四、DML(数据操作语言)
用于操作表中的数据(增、删、改)。
4.1 插入数据(INSERT)
-- 插入指定列(列与值需一一对应)
INSERT INTO 表名(列1, 列2, ...) VALUES(值1, 值2, ...);-- 插入所有列(按表结构顺序,不推荐)
INSERT INTO 表名 VALUES(值1, 值2, ...);-- 批量插入(效率更高)
INSERT INTO 表名(列1, 列2) VALUES(值1, 值2), (值1, 值2), ...;
示例:
-- 插入一条学生记录
INSERT INTO stu(sid, sname, age) VALUES(1001, '张三', 18);
-- 批量插入
INSERT INTO stu(sname, score) VALUES('李四', 90), ('王五', 85);
4.2 更新数据(UPDATE)
语法:
-- 必须加 WHERE 条件,否则更新全表!
UPDATE 表名 SET 列1=值1, 列2=值2, ... WHERE 条件;
示例:
-- 更新 id=1001 的学生年龄为 20
UPDATE stu SET age=20 WHERE sid=1001;
-- 批量更新(成绩+5,条件:班级=3)
UPDATE stu SET score=score+5 WHERE cid=3;
4.3 删除数据(DELETE)
语法:
-- 必须加 WHERE 条件,否则删除全表数据!
DELETE FROM 表名 WHERE 条件;
示例:
-- 删除 id=1002 的学生
DELETE FROM stu WHERE sid=1002;
-- 删除年龄 < 18 的学生
DELETE FROM stu WHERE age < 18;
4.4 DELETE 与 TRUNCATE 区别
| 特性 |
DELETE(DML) |
TRUNCATE(DDL) |
|---|---|---|
| 原理 | 逐条删除记录(日志可恢复) | 删除表结构后重建(不可恢复) |
| 自增影响 | 不重置自增序列(继续递增) | 重置自增序列(从 1 开始) |
| 效率 | 慢(逐行删除) | 快(直接重建表) |
五、DQL(数据查询语言)
用于查询表中数据,返回虚拟结果集(不修改原表),是 SQL 中最核心的部分。
5.1 基本查询
语法:
-- 查询指定列
SELECT 列1, 列2, ... FROM 表名;
-- 查询所有列(不推荐,效率低)
SELECT * FROM 表名;
-- 列取别名(AS 可省略)
SELECT 列1 AS 别名1, 列2 别名2 FROM 表名;
示例:
-- 查询学生的学号、姓名、成绩
SELECT sid, sname, score FROM stu;
-- 别名查询(显示“姓名”“成绩”)
SELECT sname 姓名, score 成绩 FROM stu;
5.2 条件查询(WHERE)
条件查询就是在基础查询基础上,再给sql设置条件,只查询
部分符合条件的数据条件语句 : select 字段1,字段2,... from 表名
where 字段 条件 值;
语法:
SELECT 列名 FROM 表名 WHERE 条件;
常用条件运算符:
| 类型 | 运算符 / 关键字 | 说明 |
|---|---|---|
| 比较 |
=、!=、>、<、>=、<=
|
等于、不等于、大于、小于等 |
| 逻辑 |
AND、OR、NOT
|
且、或、非 |
| 范围 | BETWEEN 值1 AND 值2 |
在值 1 到值 2 之间(包含边界) |
| 集合 |
IN(值1, 值2, ...)、NOT IN(...)
|
在 / 不在指定集合中 |
| 空值 |
IS NULL、IS NOT NULL
|
判断是否为空(不能用 = 或 !=) |
示例:
-- ============== 条件查询 ==============
-- 查询学号为1001的学生信息
select * from stu where sid = 1001;
-- 查询学生成绩大于60的学生id 姓名,成绩
select sid,sname,score from stu where score > 60;
-- 查询学生性别为女,并且年龄小于50的记录
select * from stu where sex = '女' and age < 50;
-- 查询学生学号为1001,或者姓名为李四的记录
select * from stu where sid = 1001 or sname = '李四';
-- 查询学号为1001,1002,1003的记录
select * from stu where sid = 1001 or sid = 1002 or sid = 1003;
select * from stu where sid in (1001,1002,1003);
select * from stu where sid >= 1001 and sid <= 1003;
-- 查询学号不是1001,1002,1003的记录
select * from stu where sid not in (1001,1002,1003);
select * from stu where sid != 1001 and sid != 1002 and sid != 1003;
-- 查询学生年龄在20到40之间的学生记录
select * from stu where age >= 20 and age <= 40;
select * from stu where age between 20 and 40;
-- 查询性别非男的学生记录
select * from stu where sex != '男';
select * from stu where sex = '女';
-- 查询性别为null的学生记录
update stu set sex = null where sid = 1001.;
-- 查询是不能=null运算
-- select * from stu where sex = null;
select * from stu where sex is null;
-- 查询性别不为null的学生记录
select * from stu where sex is not null;
5.3 模糊查询(LIKE)
模糊查询其实也是条件查询
用于匹配字符串的部分内容,配合通配符使用:
%:匹配任意多个字符(包括 0 个);_:匹配单个字符(开发中少用)。
示例:
-- 姓名以“张”开头
SELECT * FROM stu WHERE sname LIKE '张%';
-- 姓名中包含“三”
SELECT * FROM stu WHERE sname LIKE '%三%';
5.4 排序查询(ORDER BY)
对查询后的数据按照指定字段以及指定规则排序
desc 降序
asc 升序,默认是升序
排序查询写在最后
语法:
SELECT 列名 FROM 表名 [WHERE 条件] ORDER BY 列名 [ASC|DESC];
-- ASC:升序(默认);DESC:降序
-- 多列排序:先按列1排序,列1相同则按列2排序
示例:
-- 按年龄降序
SELECT * FROM stu ORDER BY age DESC;
-- 成绩升序,同成绩按年龄降序
SELECT * FROM stu WHERE score > 60 ORDER BY score ASC, age DESC;
5.5 聚合函数
对一列数据计算并返回单一结果(忽略
NULL值):
聚合运算完,结果只有一行数据
其他字段不能和聚合函数同时查询 ?,除非有分组查询
| 函数 | 说明 | 示例 |
|---|---|---|
COUNT(列名) |
统计该列非空行数 | SELECT COUNT(id) FROM stu; |
COUNT(*) |
统计所有行数(含 NULL) |
SELECT COUNT(*) FROM stu; |
SUM(列名) |
求和 | SELECT SUM(score) FROM stu; |
AVG(列名) |
求平均值 | SELECT AVG(age) FROM stu; |
MAX(列名) |
求最大值 | SELECT MAX(score) FROM stu; |
MIN(列名) |
求最小值 | SELECT MIN(age) FROM stu WHERE sex='男'; |
5.6 分组查询(GROUP BY)
分组查询,就是按指定列分组,对每组数据进行聚合运算。
group by 字段,根据指定字段分组
having 字段 值, 分组后再过滤
有个非常重要特点: SQL只要有分组,分成几组,查询结果就只有几行,所以一般配合聚合函数来使用,是组内数据的聚合
--------------------------------------------------------------------------------
分组查询的特点:
1) group by语句中,select后的字段必须出现group by中
或者说与聚合函数同时出现的列,必须出现在group by中
否则会报错
2) 分成几组,最终结果是几行记录
3) 聚合函数是对分组后组内聚合的
having和where都是过滤数据,什么区别?
where是分组前过滤,having是分组后过滤
where后不能使用聚合函数,having可以聚合函数
ff
语法:
SELECT 分组列, 聚合函数(列) FROM 表名
[WHERE 分组前条件] -- 先过滤再分组
GROUP BY 分组列
[HAVING 分组后条件]; -- 分组后过滤(可使用聚合函数)
核心规则:
SELECT后只能出现 分组列 或 聚合函数。
示例:
-- 按班级分组,统计每班人数和平均成绩
SELECT cid, COUNT(sid) 人数, AVG(score) 平均分 FROM stu GROUP BY cid;
-- 筛选平均分 > 80 的班级(分组后过滤)
SELECT cid, AVG(score) 平均分 FROM stu
GROUP BY cid
HAVING 平均分 > 80;
5.7 分页查询(LIMIT)
限制查询结果的行数,常用于分页展示。
就是将查询完的数据,可以限制展现条数
语法: limit n -- 限制输出指定n条,从第一条开始
limit x,y -- 限制输出,从x下标处输出y条,第一条的下标是0
语法:
SELECT 列名 FROM 表名 [WHERE 条件] LIMIT 起始索引, 每页条数;
-- 起始索引 = (页码 - 1) * 每页条数(从 0 开始)
示例:
-- 第 1 页(3 条/页)
SELECT * FROM stu LIMIT 0, 3;
-- 第 2 页(3 条/页)
SELECT * FROM stu LIMIT 3, 3;
5.8 去重查询(DISTINCT)
去除查询结果中指定列的重复值(通常配合聚合函数使用)。
示例:
-- 统计不同年龄的人数
SELECT COUNT(DISTINCT age) 不同年龄人数 FROM stu;
六、多表查询
当数据分布在多个表中时,需通过关联查询获取完整信息。
6.1 表关系类型
- 一对一:如 “用户” 与 “身份证”(一个用户对应一个身份证)。
- 一对多:如 “班级” 与 “学生”(一个班级包含多个学生)。
- 多对多:如 “订单” 与 “商品”(一个订单可含多个商品,一个商品可在多个订单中)。
6.2 内连接(INNER JOIN)
只查询两表中匹配关联条件的记录。
语法:
SELECT 字段列表 FROM 表1
INNER JOIN 表2
ON 表1.关联列 = 表2.关联列;
示例:
-- 查询学生信息及所属班级名称(stu 表 cid 关联 class 表 cid)
SELECT s.sid, s.sname, c.***ame
FROM stu s
INNER JOIN class c
ON s.cid = c.cid;
6.3 外连接
外连接又分为左外连接,右外连接 :
- 左外连接(
LEFT JOIN):保留左表所有记录,右表不匹配则为NULL。- 右外连接(
RIGHT JOIN):保留右表所有记录,左表不匹配则为NULL。
示例:
-- 左外连接:查询所有学生(含无班级的学生)及班级名称
SELECT s.sname, c.***ame
FROM stu s
LEFT JOIN class c
ON s.cid = c.cid;
-- 右外连接:查询所有班级(含无学生的班级)及学生姓名
SELECT c.***ame, s.sname
FROM stu s
RIGHT JOIN class c
ON s.cid = c.cid;
6.4 子查询(嵌套查询)
将一个查询结果作为另一个查询的条件或表。
子查询(subquery)也叫嵌套查询
1.将sql语句查询的结果当成一张表,写在from后面 必须起别名的,不起报错!
2.将sql语句当条件,写在where后面
(1)子查询作为条件
-- 单行子查询:查询年龄大于“张三”的学生
SELECT * FROM stu
WHERE age > (SELECT age FROM stu WHERE sname = '张三');
-- 多行子查询:查询与“张三”同班级的学生
SELECT * FROM stu
WHERE cid IN (SELECT cid FROM stu WHERE sname = '张三');
(2)子查询作为表(需起别名)
-- 查询男生中年龄 > 20 的用户
SELECT * FROM (
SELECT * FROM stu WHERE sex = '男' -- 子查询结果作为临时表
) AS temp
WHERE temp.age > 20;
七、SQL 执行与书写顺序
7.1 书写顺序(推荐)
SELECT 列名
FROM 表名
WHERE 条件
GROUP BY 分组列
HAVING 分组后条件
ORDER BY 排序列
LIMIT 起始索引, 条数;
7.2 执行顺序(核心)
FROM:获取表的所有数据;WHERE:过滤不符合条件的行;GROUP BY:按指定列分组;HAVING:过滤不符合条件的组;SELECT:提取指定列(含聚合运算);ORDER BY:对结果排序;LIMIT:限制返回行数。
八、DCL(数据控制语言)
用于管理用户权限和数据库安全(较少直接使用,多通过工具配置)。
| 操作 | 语法示例 | 说明 |
|---|---|---|
| 创建用户 | CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码'; |
主机名 % 表示允许远程连接 |
| 授权 | GRANT 权限 ON 库名.表名 TO '用户名'@'主机名'; |
如 GRANT SELECT ON mydb.stu TO 'test'@'%';
|
| 撤销权限 | REVOKE 权限 ON 库名.表名 FROM '用户名'@'主机名'; |
收回指定权限 |
总结
SQL 是操作关系型数据库的核心语言,需重点掌握:
- DDL:定义数据库和表结构(
CREATE、ALTER、DROP);- DML:操作数据(
INSERT、UPDATE、DELETE);- DQL:查询数据(条件、排序、聚合、分组、多表连接、子查询);
- 约束:保证数据完整性(主键、非空、外键等)。