SQL语句的分类DDL(Data Definition Languages)语句:数据定义语言这些语句定义了不同的数据段、数据库、表、列、索引等数据库对象的定义。常用的语句关键字主要包括create、drop、alter、rename、truncate。其中 create 用于创建数据库对象drop 用于删除数据库对象alter 用于修改已有对象的结构rename 用于重命名对象truncate 用于清空表中的数据但保留表结构。DDL 语句执行后通常会自动提交事务且操作不可回滚因此在使用时需要格外谨慎。DML(Data Manipulation Language)语句:数据操纵语句用于添加、删除、更新和查询数据库记录并检查数据完整性常用的语句关键字主要包括insert、delete、update等。insert 用于向表中插入新的记录delete 用于删除表中符合条件的记录update 用于修改表中已有记录的数据。与 DDL 不同DML 语句操作的是表中的数据而非表结构本身并且可以通过事务控制实现回滚从而保证数据操作的安全性和一致性。DCL(Data Control Language)语句:数据控制语句用于控制不同数据段之间的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括grant、revoke等。grant 用于向用户授予访问权限revoke 用于收回已授予的权限。通过合理使用 DCL 语句数据库管理员可以精确控制不同用户对数据库资源的访问范围有效保障数据的安全性和隐私性。DQL(Data Query Language)语句:数据查询语句用于从一个或多个表中检索信息。主要的语句关键字包括select它是数据库操作中使用频率最高、功能最丰富的语句。select 可以配合 where 条件过滤、order by 排序、group by 分组、join 多表关联以及聚合函数等子句灵活地从数据库中提取所需的数据。DQL 语句不会修改数据库中的数据只负责读取和展示查询结果是日常开发与数据分析中最常用的 SQL 类型。数据库的基本操作一.增1.创建数据库#基本用法 create database 数据库名称; #创建db1库 mysql create database db1; #创建db2库并指定默认字符集 mysql create database db2 default charset utf8mb4; #如果存在不报错(if not exists) mysql create database if not exists db3 default charset utf8mb4;2.创建数据表# 基本语法 create table 数据表名称( 字段1 字段类型 [字段约束], 字段2 字段类型 [字段约束], ... ); # 在数据库db_test中创建一个article文章表拥有4个字段编号、标题、作者、内容 mysql use db_test; mysql create table tb_article( id int not null auto_increment primary key, username varchar(20), password char(32), content text ) engineinnodb default charsetutf8mb4;3.插入数据#基本用法 insert into 数据表名称([字段1,字段2...]) values (字段1的值,字段2的值...); #向tb_article插入两条数据 mysql insert into tb_article values (null,张三,123456,内容1),(null,李四,112233,内容2); mysql insert into tb_article(username,password) values (王五,123321);二.删1.删除数据库#基本用法 drop database 数据库名称; mysql drop database db_test;2.删除数据表#基本用法 drop table 数据表名称; #删除本库的数据表tb_test(先创建create table tb_test (id int);) mysql drop table tb_test;3.删除数据#基本用法 delete from 数据表名称 [where 删除条件]; #删除tb_article中id为2的数据 mysql delete from tb_article where id2;# 清空数据表 mysql delete from 数据表; 或 mysql truncate 数据表;delete from与truncate区别在哪里delete删除数据记录数据操作语言DML在事务控制里DML语句要么commit要么rollback删除大量记录速度慢只删除数据不回收高水位线可以带条件删除truncate删除所有数据记录数据定义语言DDL不在事务控制里DDL语句执行前会提交前面所有未提交的事务清里大量数据速度快回收高水位线high water mark不能带条件删除三.改1.修改数据库的信息#不能修改数据库名称只能修改数据库编码格式 mysql alter database 数据库名称 default charset新编码格式; mysql alter database db1 default charsetgbk;2.修改数据表1.添加数据表字段#基本用法 alter table 数据表名称 add 新字段名称 字段类型 first/after 其他字段名称; #选项说明 first把新添加字段放在第一位 after 字段名称把新添加字段放在指定字段的后面 #在tb_article文章表中添加一个addtime字段类型为date(年-月-日) mysql alter table tb_article add addtime date after content; mysql desc tb_article;2.修改字段名称与字段类型注意修改字段类型必须带上原有约束如果已有数据长度超过新长度会报错类型转换比如varchar转int字符串不是数字会失败#修改字段名称与字段类型 mysql alter table tb_article change username user varchar(40); mysql desc tb_article; #只修改字段的类型 mysql alter table tb_article modify user varchar(50); mysql desc tb_article; #只修改字段名称类型不变 mysql alter table tb_article change password passwd char(32); #mysql8.0 mysql alter table tb_article rename column password to passwd;3.删除某个字段#基本用法 alter table tb_article drop 字段名称; #删除article表中的addtime字段 mysql alter tb_article drop addtime; mysql desc tb_article;4.修改数据表引擎mysql alter table tb_article enginemyisam; mysql show create table tb_article;5.修改数据表的编码格式mysql alter table tb_article default charsetgbk; mysql show create table tb_article;6.修改数据表名称#移动表到另一个库里并重命名 rename table db_test.tb_article to db1.article; 或者(use db1;show tables;) alter table db1.artile rename db_test.tb_article; #只重命名表名不移动 rename table tb_article to article; 或者(show tables;) alter table article rename tb_article;3.修改数据#基本用法 update 数据表名称 set 字段1更新后的值,字段2更新后的值,... where 更新条件; #将username张三这条数据的conten修改为法外狂徒 mysql update tb_article set content法外狂徒 where name张三;四.查1.查询已创建的数据库#显示所有数据库 mysql show databases; #显示某个数据库的数据结构 mysql show create database db1;2.查询已创建数据表#查询当前数据库所有数据表 mysql use 数据库名称; mysql show tables; #查询数据表的创建过程 mysql show create table 数据表名称; 或 mysql desc 数据表名称;3.查询数据# 基本用法 select * from 数据表名称 [where 查询条件]; select id,username from 数据表名称 [where 查询条件]; # 简单示例查询tb_article表中的所有记录 mysql select * from tb_article; # 简单示例查询tb_article表中id,username字段对应的信息 mysql select id,username from tb_article; # 简单示例查询tb_article表中id2的所有信息 mysql select * from tb_article where id2; # 简单示例查询tb_article表中name为张三的信息 mysql select * from tb_article where name张三;详细使用见七.sql查询语句五.用户权限1.用户管理1.创建用户MySQL中不能单纯通过用户名来说明用户必须要加上主机。如jack10.1.1.1,且在mysql服务器上书写创建用户的语句# 基本用法 create user 用户名被允许连接的主机名称或主机的IP地址 identified by 用户密码; # 创建一个MySQL账号用户名tom用户密码123 mysql create user tomlocalhost identified by 123; 或 mysql create user tom127.0.0.1 identified by 123; # 创建一个MySQL账号要求开通远程连接主机IP地址10.1.1.23用户名harry用户密码123 mysql create user harry10.1.1.23 identified by 123; # 创建一个MySQL账号要求开通远程连接要求面向所有主机开放用户名root用户密码123 mysql create user root% identified by 123;2.删除用户# 基本用法 mysql drop user 用户名主机名称或主机的IP地址; #注意 如果在删除用户时没有指定主机的名称或主机的IP地址则默认删除这个账号的所有信息。 # 删除tom这个账号 mysql drop user tomlocalhost; # 删除harry这个账号 mysql drop user harry10.1.1.%;3.修改用户MySQL用户重命名通常可以更改两部分一部分是用户的名称一部分是被允许访问的主机名称或主机的IP地址。# 基本用法 mysql rename user 旧用户信息 to 新用户信息; # 把用户root%更改为rootlocalhost mysql rename user root% to rootlocalhost; # 把tomlocalhost更名为harrylocalhost mysql create user tomlocalhost identified by 123; mysql rename user tomlocalhost to harrylocalhost;2.权限管理1.授予权限# 基本用法 mysql grant 权限1,权限2 on 库.表 to 用户主机 mysql grant 权限(列1,列2,...) on 库.表 to 用户主机 # 给tom账号分配db1的查询权限 mysql grant select on db_test.* to tomlocalhost; mysql flush privileges; # 给tom账号分配db_test数据的tb.article数据表的查询权限要求只能更改class_name字段 mysql grant select(user) on db_test.tb.article to tomlocalhost; mysql flush privileges # 添加一个root%账号然后分配所有权限 mysql create user root% identified by 123; mysql grant all on *.* to root%; mysql flush privileges;2.查询权限# 查询当前用户权限 show grants; # 查询其他用户权限 show grants for 用户名称授权的主机名称或IP地址;3.转发权限with grant option选项作用代表此账号可以向其他用户转发其拥有的权限但是转发的权限不能超过自身权限。如果grant授权时没有with grant option选项则其无法为其他用户转发授权。# root授予test转发权限的权力 mysql grant all on *.* to testlocalhost with grant option; # 创建test1用户后再登录test去授予其查询的权限 mysqlgrant select on db_test.* to testlocalhost; # root没有授予test2转发权限的权力 mysql grant all on *.* to test2localhost identified by 123; # 创建test3后登录test2尝试转发权限会报错4.回收权限# 基本用法 revoke 权限 on 库.表 from 用户; # 撤消指定的权限(回收tom的db_test库,tb_article表的select权限) mysql revoke select on db_test.tb_article from tomlocalhost; mysql flush privileges; mysql show grants for tomlocalhost; # 撤消所有的权限 mysql revoke all on *.* from tomlocalhost;六.数据类型数值-整数类型tinyint1 字节范围最小常用来做状态标识0/1smallint2 字节mediumint3 字节int4 字节开发最常用主键 / 普通数字字段bigint8 字节数值很大时使用雪花 ID、大自增主键推荐数值-小数类型DECIMAL/UMERIC定点数精度绝对准确。适合金额、财务计算不会丢失精度可自定义总长度和小数位数。。FLOAT:单精度浮点数4 字节大约 7 位有效数字数值越大精度越低不适合金额。DOUBLE:双精度浮点数8 字节大约 15 位有效数字同样是近似存储存在精度丢失风险。字符串类型CHAR定长字符串长度 0~255。分配固定存储空间不足长度自动空格填充读取时尾部空格移除。占用空间和字符集相关utf8 一个中文 3 字节gbk 中文 2 字节。查询速度快适合长度固定内容手机号、身份证。VARCHAR变长字符串按需占用空间。额外用 1~2 字节记录真实数据长度MySQL 上限 65535 字节实际可用 65532 字节。适合长短不一的文本名称、简介。TEXT大文本类型。当文本长度超出 VARCHAR 合适范围时选用适合长文章、大段文字不能设置默认值。时间类型DATE日期YYYY-MM-DD只存年月日。TIME时间HH:MM:SS只存时分秒。DATETIME日期时间YYYY-MM-DD HH:MM:SS范围大不受时区影响业务开发首选。TIMESTAMP时间戳YYYY-MM-DD HH:MM:SS底层存时间戳受时区影响范围比 DATETIME 小。YEAR年份类型仅保存年份。其他类型BLOB保存二进制的大型数据字节串没有字符集如图片、音频视频等。ENUM枚举类型多选一从给定的多个选项中选择一个如gender enum(男,女,保密)ET集合类型多选多从给定的多个选项中选个多个如hobby set(吃饭,睡觉,打豆豆)七.sql查询语句常用符号说明符号说明%匹配0个或任意多个字符_匹配单个字符like模糊匹配等于,精确匹配大于小于大于等于小于等于! 或 不等于! 或 not逻辑非|| 或 or逻辑或 或 and逻辑与between ...and...两者之间包括边界in(...)在...not in(...)不在...简单统计函数常见统计函数说明max求最大值min求最小值avg求平均值sum求总和count求总行数测试用表建表CREATE TABLE student_score ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, student_name VARCHAR(20) NOT NULL COMMENT 学生姓名, class_name VARCHAR(20) NOT NULL COMMENT 班级, subject VARCHAR(20) NOT NULL COMMENT 科目, score TINYINT NOT NULL COMMENT 分数, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;说明ENGINEInnoDB:指定存储引擎默认事务引擎DEFAULT CHARSETutf8mb4:字符集完整支持中文、emojiCOLLATEutf8mb4_unicode_ci:排序规则ci代表大小写不敏感插入数据INSERT INTO student_score (student_name,class_name,subject,score) VALUES (张三,一班,MySQL,88), (张三,一班,Java,76), (李四,一班,MySQL,92), (李四,一班,Java,81), (王五,二班,MySQL,59), (王五,二班,Java,66), (赵六,二班,MySQL,77), (赵六,二班,Java,95), (孙七,一班,MySQL,45), (孙七,一班,Java,72), (周八,二班,MySQL,83), (周八,二班,Java,89);mysql select * from student_score; ------------------------------------------------------------------- | id | student_name | class_name | subject | score | create_time | ------------------------------------------------------------------- | 1 | 张三 | 一班 | MySQL | 88 | 2026-10-09 13:56:50 | | 2 | 张三 | 一班 | Java | 76 | 2026-10-09 13:56:50 | | 3 | 李四 | 一班 | MySQL | 92 | 2026-10-09 13:56:50 | | 4 | 李四 | 一班 | Java | 81 | 2026-10-09 13:56:50 | | 5 | 王五 | 二班 | MySQL | 59 | 2026-10-09 13:56:50 | | 6 | 王五 | 二班 | Java | 66 | 2026-10-09 13:56:50 | | 7 | 赵六 | 二班 | MySQL | 77 | 2026-10-09 13:56:50 | | 8 | 赵六 | 二班 | Java | 95 | 2026-10-09 13:56:50 | | 9 | 孙七 | 一班 | MySQL | 45 | 2026-10-09 13:56:50 | | 10 | 孙七 | 一班 | Java | 72 | 2026-10-09 13:56:50 | | 11 | 周八 | 二班 | MySQL | 83 | 2026-10-09 13:56:50 | | 12 | 周八 | 二班 | Java | 89 | 2026-10-09 13:56:50 | -------------------------------------------------------------------1.where子句#查询科目是 MySQL 的所有成绩 SELECT * FROM student_score WHERE subject MySQL; #查询分数大于 80 分的记录 SELECT * FROM student_score WHERE score 80; #查询分数小于 60 分不及格 SELECT * FROM student_score WHERE score 60; #分数≥90 分 SELECT * FROM student_score WHERE score 90; #分数≤70 分 SELECT * FROM student_score WHERE score 70; #查询班级不是一班的数据两种写法等价 SELECT * FROM student_score WHERE class_name ! 一班; 或 SELECT * FROM student_score WHERE class_name 一班; #一班并且 MySQL 科目分数 80 SELECT * FROM student_score WHERE class_name一班 AND subjectMySQL AND score80; #分数大于 90 或者 小于 60 SELECT * FROM student_score WHERE score 90 OR score 60; #查询不是 Java 科目的数据 SELECT * FROM student_score WHERE NOT subject Java; SELECT * FROM student_score WHERE subject ! Java; #查询姓名以 “张” 开头的学生 SELECT * FROM student_score WHERE student_name LIKE 张%; #姓名是两个字第一个字是 “赵”赵_ SELECT * FROM student_score WHERE student_name LIKE 赵_; #分数在 70 ~ 90 之间包含 70 和 90 SELECT * FROM student_score WHERE score BETWEEN 70 AND 90; #查询姓名是张三、李四的记录 SELECT * FROM student_score WHERE student_name IN (张三,李四); #查询姓名不是张三、李四的记录 SELECT * FROM student_score WHERE student_name NOT IN (张三,李四); #一班学生分数大于 70科目是 MySQL 或者 Java排除张三 SELECT * FROM student_score WHERE class_name一班 AND score70 AND subject IN (MySQL,Java) AND student_name NOT IN (张三);2.group by子句#按班级分组统计每个班级多少条成绩记录 SELECT class_name, COUNT(*) AS record_count FROM student_score GROUP BY class_name; #按学科分组统计每个班级的平均分 SELECT subject, AVG(score) AS avg_score FROM student_score GROUP BY subject; #按学生姓名分组求每个学生总分、平均分、最高分、最低分 SELECT student_name, SUM(score) AS total_score, AVG(score) AS avg_score, MAX(score) AS max_score, MIN(score) AS min_score FROM student_score GROUP BY student_name;3.having子句# GROUP BY HAVING筛选【学生总分大于 150】的学生 SELECT student_name, SUM(score) AS total_score FROM student_score GROUP BY student_name HAVING SUM(score) 150; # WHERE 先过滤原始数据再 GROUP BY 分组再 HAVING 过滤分组结果 SELECT student_name, AVG(score) AS java_avg FROM student_score WHERE subject Java GROUP BY student_name HAVING AVG(score) 75; # 按班级分组求班级 MySQL 科目平均分只保留平均分大于 70 的班级 SELECT class_name, AVG(score) mysql_avg FROM student_score WHERE subject MySQL GROUP BY class_name HAVING AVG(score) 70; # 综合按班级 科目两个字段联合分组 SELECT class_name, subject, AVG(score) AS avg_score FROM student_score GROUP BY class_name, subject HAVING AVG(score) 80; # 按班级分组计算各班总分只展示班级总分大于 300 的班级 SELECT class_name,SUM(score) AS total_score FROM student_score GROUP BY class_name HAVING SUM(score) 300;4.order by子句# 按分数降序分数高的在前 SELECT student_name,subject,score FROM student_score ORDER BY score DESC; # 只看 MySQL 科目分数从小到大排序 SELECT student_name,score FROM student_score WHERE subjectMySQL ORDER BY score ASC; # 先按班级升序同班内部按分数降序 SELECT class_name,student_name,subject,score FROM student_score ORDER BY class_name ASC, score DESC; # 先按班级升序同班内部按Java科目分数降序 SELECT class_name,student_name,subject,score FROM student_score WHERE subjectJava ORDER BY class_name ASC, score DESC;5.limit子句# ORDER BY LIMIT 取Top3分数最高的3条成绩 SELECT student_name,subject,score FROM student_score ORDER BY score DESC LIMIT 3; #查询所有 Java 科目成绩分数降序只取前 4 名 SELECT student_name,subject,score FROM student_score WHERE subjectJava ORDER BY score DESC LIMIT 4; # 分页写法LIMIT offset,rows跳过前2条取后面3条 SELECT student_name,subject,score FROM student_score ORDER BY score DESC LIMIT 2,3; # 按班级 科目分组计算平均分只保留平均分80的分组平均分降序只取前2条 SELECT class_name, subject, AVG(score) AS avg_score FROM student_score GROUP BY class_name, subject HAVING AVG(score) 80 ORDER BY avg_score DESC LIMIT 2;6.多表查询新建teacher教师表CREATE TABLE teacher ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 教师id, t_name VARCHAR(20) NOT NULL COMMENT 教师姓名, subject VARCHAR(20) NOT NULL COMMENT 授课科目, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;插入测试数据INSERT INTO teacher(t_name,subject) VALUES (李老师,MySQL), (王老师,Java), (陈老师,Python), (刘老师,MySQL);mysql select * from teacher; --------------------------------------------- | id | t_name | subject | create_time | --------------------------------------------- | 1 | 李老师 | MySQL | 2026-10-09 15:27:42 | | 2 | 王老师 | Java | 2026-10-09 15:27:42 | | 3 | 陈老师 | Python | 2026-10-09 15:27:42 | | 4 | 刘老师 | MySQL | 2026-10-09 15:27:42 | ---------------------------------------------1.union联合查询作用把多条 SELECT 语句的结果纵向拼接上下叠加注意多条 select 的列数量必须一致列的数据类型顺序要对应UNION自动去重UNION ALL不去重性能更高常用字段名以第一条 select 的列名为准# union自动去重 # 取出所有学生科目 和 所有教师授课科目合并去掉重复科目 SELECT subject FROM student_score UNION SELECT subject FROM teacher; # union all 不去重直接拼接 # 展示全部记录重复的 MySQL、Java 都会保留性能比 UNION 更好 SELECT subject FROM student_score UNION ALL SELECT subject FROM teacher; # 查询80分以上的学生姓名和全部老师姓名 SELECT student_name AS name FROM student_score WHERE score 80 UNION ALL SELECT t_name AS name FROM teacher; # 联合查询时排序要写在整体联合查询的最后 SELECT subject FROM student_score UNION SELECT subject FROM teacher ORDER BY subject;2.交叉查询含义A 表每一行 和 B 表每一行全部两两组合没有匹配条件不写ON结果行数 A 表行数 × B 表行数数据量大的时候结果会爆炸式增长# 查学生姓名、老师姓名、科目 SELECT s.student_name, t.t_name, s.subject FROM student_score s CROSS JOIN teacher t; # student_score和teacher交叉连接只看MySQL科目的组合 SELECT s.student_name,t.t_name,s.subject FROM student_score s CROSS JOIN teacher t; where s.sbject MySQL AND t.sbjectMySQL;3.内连接查询# 基本用法 mysql select 数据表1.字段列表,数据表2.字段列表 from 数据表1 inner join 数据表2 on 连接条件; # 查询学生姓名、学生分数、老师姓名、科目只取出科目相同的记录 SELECT s.student_name, s.score, t.t_name, s.subject FROM student_score s INNER JOIN teacher t ON s.subject t.subject; # 查询科目相同并且学生分数大于80的师生信息 SELECT s.student_name, s.score, t.t_name, s.subject FROM student_score s INNER JOIN teacher t ON s.subject t.subject WHERE s.score 80; # 按老师分组统计每个老师对应的学生平均分 SELECT t.t_name, AVG(s.score) AS avg_score FROM student_score s INNER JOIN teacher t ON s.subject t.subject GROUP BY t.t_name;4.外连接查询# 基本用法 select 数据表1.字段列表,数据表2.字段列表 from 数据表1 left join 数据表2 on 连接条件; # 学生姓名、班级、分数、科目、授课老师 SELECT s.student_name, s.class_name, s.score, s.subject, t.t_name FROM student_score s LEFT JOIN teacher t ON s.subject t.subject; # 统计每个学生的成绩以及对应的授课老师只看一班学生 SELECT s.student_name, s.subject, s.score, t.t_name FROM student_score s LEFT JOIN teacher t ON s.subject t.subject WHERE s.class_name 一班; # 右连接与左连接类似但是可读性差一般不用 # 查询全部老师以及对应学生成绩没有学生的老师信息也保留 SELECT s.student_name, s.score, t.t_name, t.subject FROM student_score s RIGHT JOIN teacher t ON s.subject t.subject;7.子查询一条 SELECT 语句里面嵌套另外一条 SELECT 语句嵌套的这一段就是子查询注意子查询优先执行子查询结果作为外层 SQL 的条件 / 数据源子查询尽量不要返回大量数据性能一般关键字IN/NOT IN/ /EXISTS# 查询分数高于平均分的所有学生成绩 SELECT * FROM student_score WHERE score (SELECT AVG(score) FROM student_score); # 查询有老师授课的科目对应的学生成绩 SELECT * FROM student_score WHERE subject IN (SELECT subject FROM teacher); # 查询科目没有授课老师的学生成绩 SELECT * FROM student_score WHERE subject NOT IN (SELECT subject FROM teacher); # 查询存在授课老师的学生成绩 SELECT * FROM student_score s WHERE EXISTS (SELECT 1 FROM teacher t WHERE s.subject t.subject); # 先算出每个学生总分再查询总分大于150的学生 SELECT * FROM ( SELECT student_name, SUM(score) AS total_score FROM student_score GROUP BY student_name ) AS temp_stu WHERE total_score 150; # 查询学生姓名、科目、分数同时展示全部学生平均分 SELECT student_name, subject, score, (SELECT AVG(score) FROM student_score) AS all_avg_score FROM student_score;