数据库
数据库的好处
1.持久化数据到本地
2.可以实现结构化查询,方便管理
数据库相关概念
1、DB:数据库,保存一组有组织的数据的容器
2、DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据
3、SQL:结构化查询语言,用于和DBMS通信的语言
数据库存储数据的特点
1、将数据放到表中,表再放到库中
2、一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。
3、表具有一些特性,这些特性定义了数据在表中如何存储,类似java中 "类"的设计。
4、表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java 中的"属性"
5、表中的数据是按行存储的,每一行类似于java中的"对象"。
MySQL产品的介绍和安装
MySQL服务的启动和停止
方式一:计算机------右击管理------服务
方式二:通过管理员身份运行
net start 服务名(启动服务)
net stop 服务名(停止服务)
MySQL服务的登录和退出
方式一:通过mysql自带的客户端
只限于root用户
mysql
方式二:通过windows自带的客户端
登录:
mysql 【-h主机名 -P端口号 】-u用户名 -p密码
退出:
exit或ctrl+C
MySQL的常见命令
mysql
1.查看当前所有的数据库
show databases;
2.打开指定的库
use 库名
3.查看当前库的所有表
show tables;
4.查看其它库的所有表
show tables from 库名;
5.创建表
create table 表名(
列名 列类型,
列名 列类型,
。。。
);
6.查看表结构
desc 表名;
mysql
7.查看服务器的版本
方式一:登录到mysql服务端
select version();
方式二:没有登录到mysql服务端
mysql --version
或
mysql --V
MySQL的语法规范
1.不区分大小写,但建议关键字大写,表名、列名小写
2.每条命令最好用分号结尾
3.每条命令根据需要,可以进行缩进 或换行
4.注释
单行注释:#注释文字
单行注释:-- 注释文字
多行注释:/* 注释文字 */
SQL的语言分类
DQL(Data Query Language):数据查询语言
select
DML(Data Manipulate Language):数据操作语言
insert 、update、delete
DDL(Data Define Language):数据定义语言
create、drop、alter
TCL(Transaction Control Language):事务控制语言
commit、rollback
SQL的常见命令
show databases; 查看所有的数据库
use 库名; 打开指定 的库
show tables ; 显示库中的所有表
show tables from 库名;显示指定库中的所有表
create table 表名(
字段名 字段类型,
字段名 字段类型
); 创建表
desc 表名; 查看指定表的结构
select * from 表名;显示表中的所有数据
MySQL管理
启动mysql服务器:
mysql
net start mysql
关闭mysql服务器:
mysql
net stop mysql
创建用户
要创建一个新用户,你可以使用以下 SQL 命令:
mysql
CREATE USER 'wzx'@'localhost' IDENTIFIED BY '123456';
username:用户名。host:指定用户可以从哪些主机连接。例如,localhost仅允许本地连接,%允许从任何主机连接。password:用户的密码。
授权权限
创建用户后,你需要授予他们访问权限,使用 GRANT 命令来授予权限:
mysql
GRANT privileges ON database_name.* TO 'username'@'host';
privileges:所需的权限,如ALL PRIVILEGES、SELECT、INSERT、UPDATE、DELETE等。database_name.*:表示对某个数据库或表授予权限。database_name.*表示对整个数据库的所有表授予权限,database_name.table_name表示对指定的表授予权限。TO 'username'@'host':指定授予权限的用户和主机。
实例
mysql
GRANT ALL PRIVILEGES ON test_db.* TO 'wzx'@'localhost';
刷新权限
授予或撤销权限后,需要刷新权限使更改生效:
mysql
FLUSH PRIVILEGES;
查看用户权限
要查看特定用户的权限,可以使用以下命令:
mysql
SHOW GRANTS FOR 'username'@'host';
实例
mysql
SHOW GRANTS FOR 'wzx'@'localhost';
撤销权限
要撤销用户的权限,使用 REVOKE 命令:
mysql
REVOKE privileges ON database_name.* FROM 'wzx'@'localhost';
实例
mysql
REVOKE ALL PRIVILEGES ON test_db.* FROM 'john'@'localhost';
删除用户
如果需要删除用户,可以使用以下命令:
mysql
DROP USER 'wzx'@'localhost';
修改用户密码
要修改用户的密码,可以使用 ALTER USER 命令:
mysql
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';
实例
mysql
ALTER USER 'john'@'localhost' IDENTIFIED BY 'newpassword456';
修改用户主机
要更改用户的主机(即允许从哪些主机连接),可以先删除用户,再重新创建一个新的用户。
实例
-- 删除旧用户
mysql
DROP USER 'john'@'localhost';
-- 重新创建用户并指定新的主机
mysql
CREATE USER 'john'@'%' IDENTIFIED BY 'password123';
创建用户时指定权限
在创建用户时,也可以同时授予权限(在 MySQL 8.0.16 及更高版本):
实例
mysql
CREATE USER 'john'@'localhost' IDENTIFIED BY 'password123' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON test_db.* TO 'john'@'localhost';
DQL语言的学习
进阶1:基础查询
语法:
SELECT 要查询的东西
【FROM 表名】;
mysql
类似于Java中 :System.out.println(要打印的东西);
特点:
①通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
进阶2:条件查询
条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法:
select
要查询的字段|表达式|常量值|函数
from
表
where
条件 ;
mysql
分类:
一、条件表达式
示例:salary>10000
条件运算符:
> < >= <= = != <>
二、逻辑表达式
示例:salary>10000 && salary<20000
逻辑运算符:
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true
三、模糊查询
示例:last_name like 'a%'
进阶3:排序查询
mysql
语法:
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc|desc】
-- 2. 多字段排序:先按状态升序,再按金额降序
SELECT order_id, user_id, order_amount, order_status
FROM order_main
ORDER BY order_status ASC, order_amount DESC;
-- 5. 按「价格×库存」表达式排序(直接用计算式排序)
SELECT product_name, price, stock, price * stock AS total_value
FROM product
ORDER BY price * stock DESC;
-- 6. 按「用户名长度」函数排序(LENGTH() 函数返回字符串长度)
SELECT username, phone, LENGTH(username) AS name_length
FROM user_info
ORDER BY LENGTH(username) ASC;
-- 7. 按别名 total_value 排序(推荐写法,更简洁)
SELECT product_name, price, stock, price * stock AS total_value
FROM product
ORDER BY total_value DESC;
-- 8. 按别名 amount_div_100 排序
SELECT order_id, order_amount, order_amount / 100 AS amount_div_100
FROM order_main
ORDER BY amount_div_100 ASC;
进阶4:常见函数
一、单行函数
mysql
1、字符函数
concat拼接
substr截取子串
upper转换成大写
lower转换成小写
trim去前后指定的空格和字符
ltrim去左边空格
rtrim去右边空格
replace替换
lpad左填充
rpad右填充
instr返回子串第一次出现的索引
length 获取字节个数
-- 1. concat:拼接字符串(常用:拼接用户名+手机号)
SELECT CONCAT(username, ' - ', phone) AS user_info FROM user_info WHERE user_id = 1;
-- 结果:zhangsan - 13800138000
-- 2. substr:截取子串(语法:substr(字符串, 起始索引, 长度),索引从1开始)
SELECT SUBSTR(product_name, 1, 2) AS short_name FROM product WHERE product_id = 1; -- 截取前2个字符
-- 结果:小米
SELECT SUBSTR(product_name, 3) AS short_name FROM product WHERE product_id = 1; -- 从第3位截取到末尾
-- 结果:14手机
-- 3. upper:转大写
SELECT UPPER(username) AS upper_name FROM user_info WHERE user_id = 1;
-- 结果:ZHANGSAN
-- 4. lower:转小写
SELECT LOWER('HUAWEIMate60') AS lower_name;
-- 结果:huaweimate60
-- 5. trim:去除前后指定字符(默认去空格,也可指定字符)
SELECT TRIM(' 罗技机械键盘 ') AS trim_space; -- 去空格
-- 结果:罗技机械键盘
SELECT TRIM('x' FROM 'xxx金士顿U盘xxx') AS trim_char; -- 去前后的x
-- 结果:金士顿U盘
-- 6. ltrim:去左边空格
SELECT LTRIM(' 苹果iPad Pro') AS ltrim_result;
-- 结果:苹果iPad Pro
-- 7. rtrim:去右边空格
SELECT RTRIM('华为Mate60 ') AS rtrim_result;
-- 结果:华为Mate60
-- 8. replace:替换字符(将商品名中的「手机」替换为「智能手机」)
SELECT REPLACE(product_name, '手机', '智能手机') AS new_name FROM product WHERE category = '手机';
-- 结果:小米14智能手机、华为Mate60智能手机
-- 9. lpad:左填充(用指定字符填充到指定长度,长度不足时截断)
SELECT LPAD(price, 8, '0') AS lpad_price FROM product WHERE product_id = 5; -- 价格89.00填充为8位,左边补0
-- 结果:0089.00
-- 10. rpad:右填充(用指定字符填充到指定长度)
SELECT RPAD(product_name, 10, '-') AS rpad_name FROM product WHERE product_id = 4;
-- 结果:罗技机械键盘--
-- 11. instr:返回子串第一次出现的索引(无则返回0)
SELECT INSTR(product_name, 'a') AS index_pos FROM product WHERE product_id = 3;
-- 结果:5(「苹果iPad Pro」中「盘」在第5位)
-- 12. length:获取字节数(utf8mb4中,中文占4字节,数字/字母占1字节)
SELECT LENGTH(product_name) AS byte_count FROM product WHERE product_id = 1;
-- 结果:10(「小米14手机」:小(4)+米(4)+1(1)+4(1)+手(4)+机(4) → 实际计算:4+4+1+1+4+4=18?注:不同字符集可能有差异,以实际运行为准)
2、数学函数
round 四舍五入
rand 随机数
floor向下取整
ceil向上取整
mod取余
truncate截断
# 数学函数
-- 1. round:四舍五入(round(数值, 保留小数位))
SELECT ROUND(price, 1) AS round_price FROM product WHERE product_id = 1; -- 4999.00保留1位小数
-- 结果:4999.0
SELECT ROUND(5999.567); -- 无小数位,四舍五入
-- 结果:5999(或6000,取决于MySQL版本,核心是四舍五入逻辑)
-- 2. rand:生成0~1之间的随机数(常用:生成1~100的随机数)
SELECT RAND() AS random_num; -- 结果示例:0.87654321
SELECT FLOOR(RAND() * 100) + 1 AS random_1_100; -- 1~100的整数随机数
-- 3. floor:向下取整(取小于等于数值的最大整数)
SELECT FLOOR(price / 1000) AS floor_price FROM product WHERE product_id = 2; -- 5999.00/1000=5.999,向下取整
-- 结果:5
-- 4. ceil:向上取整(取大于等于数值的最小整数)
SELECT CEIL(price / 1000) AS ceil_price FROM product WHERE product_id = 2;
-- 结果:6
-- 5. mod:取余(等价于 % 运算符)
SELECT MOD(stock, 7) AS mod_stock FROM product WHERE product_id = 1; -- 100%7=2
-- 结果:2
-- 6. truncate:截断(直接截断小数位,不四舍五入)
SELECT TRUNCATE(5999.999, 1) AS trunc_price; -- 保留1位小数,截断
-- 结果:5999.9
3、日期函数
now当前系统日期+时间
curdate当前系统日期
curtime当前系统时间
str_to_date 将字符转换成日期
date_format将日期转换成字符
-- 1. now:当前系统日期+时间
SELECT NOW() AS current_datetime;
-- 结果示例:2026-01-20 15:30:25
-- 2. curdate:当前系统日期(仅日期)
SELECT CURDATE() AS current_date;
-- 结果示例:2026-01-20
-- 3. curtime:当前系统时间(仅时间)
SELECT CURTIME() AS current_time;
-- 结果示例:15:30:25
-- 4. str_to_date:字符转日期(按指定格式解析,常用:处理前端传入的日期字符串)
SELECT STR_TO_DATE('2026-01-20', '%Y-%m-%d') AS str_to_date;
-- 结果:2026-01-20
SELECT STR_TO_DATE('2026/01/20 15:30', '%Y/%m/%d %H:%i') AS str_to_datetime;
-- 结果:2026-01-20 15:30:00
-- 5. date_format:日期转字符(按指定格式输出,常用:展示友好的日期)
SELECT create_time, DATE_FORMAT(create_time, '%Y年%m月%d日 %H:%i:%s') AS fmt_create_time FROM user_info WHERE user_id = 1;
-- 结果示例:2026-01-20 10:00:00 → 2026年01月20日 10:00:00
4、流程控制函数
if 处理双分支
case语句 处理多分支
情况1:处理等值判断
情况2:处理条件判断
# 流程控制
-- 1. if:双分支(语法:IF(条件, 满足时返回值, 不满足时返回值))
-- 示例:判断商品价格是否大于1000,标注「高价」/「平价」
SELECT product_name, price, IF(price > 1000, '高价', '平价') AS price_level FROM product;
-- 结果:小米14手机(4999)→ 高价;罗技键盘(299)→ 平价
-- 2. case:多分支(情况1:等值判断)
-- 示例:将订单状态码转换为中文描述
SELECT order_id, order_status,
CASE order_status
WHEN 0 THEN '待付款'
WHEN 1 THEN '已付款'
WHEN 2 THEN '已发货'
WHEN 3 THEN '已完成'
WHEN 4 THEN '已取消'
ELSE '未知状态'
END AS status_desc
FROM order_main;
-- 结果:订单1(status=2)→ 已发货;订单3(status=3)→ 已完成
-- 3. case:多分支(情况2:条件判断)
-- 示例:按价格区间分类商品
SELECT product_name, price,
CASE
WHEN price > 5000 THEN '高端商品'
WHEN price > 1000 THEN '中端商品'
ELSE '低端商品'
END AS price_category
FROM product;
-- 结果:华为Mate60(5999)→ 高端;小米14(4999)→ 中端;金士顿U盘(89)→ 低端
5、其他函数
version版本
database当前库
user当前连接用户
# 其他函数
-- 1. version:查看MySQL版本
SELECT VERSION() AS mysql_version;
-- 结果示例:8.0.36
-- 2. database:查看当前使用的数据库
SELECT DATABASE() AS current_db;
-- 结果:demo_ecommerce
-- 3. user:查看当前连接的用户
SELECT USER() AS current_use;
-- 结果示例:root@localhost
二、分组函数
mysql
sum 求和
max 最大值
min 最小值
avg 平均值
count 计数
# count 需要注意的点 COUNT:计数
-- 示例1:统计商品总数(COUNT(*):统计行数,包含NULL值)
SELECT COUNT(*) AS product_count FROM product;
-- 结果:5
-- 示例2:统计有手机号的用户数(COUNT(字段):排除NULL值)
SELECT COUNT(phone) AS user_with_phone FROM user_info;
-- 结果:3(所有用户都有手机号)
-- 示例3:统计不同订单状态的数量(COUNT(DISTINCT):去重计数)
SELECT COUNT(DISTINCT order_status) AS distinct_status_count FROM order_main;
-- 结果:3(状态2、1、3)
# 综合例句
-- 3. 按订单状态,统计每种状态的订单数、平均金额
SELECT
order_status,
CASE order_status -- 配合流程函数,状态码转中文
WHEN 0 THEN '待付款'
WHEN 1 THEN '已付款'
WHEN 2 THEN '已发货'
WHEN 3 THEN '已完成'
WHEN 4 THEN '已取消'
ELSE '未知'
END AS status_desc,
COUNT(*) AS status_count,
AVG(order_amount) AS status_avg_amount
FROM order_main
GROUP BY order_status; -- 按状态码分组(别名不能用于GROUP BY)
-- 结果:
-- 状态1(已付款):1单,平均7999.00
-- 状态2(已发货):1单,平均5298.00
-- 状态3(已完成):1单,平均89.00
特点:
1、以上五个分组函数都忽略null值,除了count(*)
2、sum和avg一般用于处理数值型
max、min可以处理字符串,日期,数值,(数值比较,字符按照ASCII/UTF-8进行比较)
count可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持:
字段、*、常量值,一般放1
建议使用 count(*)可以统计null
关键补充(新手必看)!!!!!!
1、COUNT(*) 统计所有行数(包含 NULL 字段),COUNT(字段) 统计该字段非 NULL 的行数,COUNT(DISTINCT 字段) 统计去重后的非 NULL 行数。
2、GROUP BY 后可以跟多个字段(如 GROUP BY a,b),表示按多个字段的组合分组。
3、分组函数不能用在 WHERE 子句中(如 WHERE SUM(price) > 1000 是错误的),必须用 HAVING。
4、GROUP BY 子句中只能用原始字段名,不能用查询别名(如 GROUP BY status_desc 错误)。
5、分组函数(SUM/MAX/MIN/AVG/COUNT)用于统计数据,单独使用时统计全表,配合 GROUP BY 时按指定维度分组统计。
6、HAVING 用于过滤分组结果,需跟在 GROUP BY 后,可使用分组函数;WHERE 用于过滤行,不能用分组函数。
7、实战中最常用的是「GROUP BY + 分组函数 + HAVING」的组合,用于按类别统计并筛选有效数据。
对于avg的小数处理
实战中:
# 使用ROUND
-- 示例1:平均价格四舍五入保留1位小数
SELECT ROUND(AVG(price), 1) AS avg_price_round FROM product;
-- 结果:3857.0(因为原始结果是整数)
# 使用TRUNCATE
-- 示例:外设分类平均价格,截断保留1位小数
SELECT
category,
AVG(price) AS avg_price_original, -- 249.45
TRUNCATE(AVG(price), 1) AS avg_price_truncate -- 249.4(直接截断,不是249.5)
FROM product
WHERE category = '外设'
GROUP BY category;
# 使用FORMAT
-- 示例:订单平均金额格式化(保留2位,带千分位)
SELECT
AVG(order_amount) AS avg_original, -- 4462.00
FORMAT(AVG(order_amount), 2) AS avg_format -- '4,462.00'(字符串)
FROM order_main;
进阶5:分组查询
语法:
select 查询的字段,分组函数
from 表
group by 分组的字段
mysql
特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
针对的表 位置 关键字
分组前筛选: 原始表 group by的前面 where
分组后筛选: 分组后的结果集 group by的后面 having
4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名
SELECT
user_id AS 用户ID,
SUM(order_amount) AS 消费总额,
COUNT(*) AS 订单数
FROM order_main
GROUP BY user_id
ORDER BY 消费总额 DESC;
关键注意事项(新手避坑)
分组字段规则:SELECT 中出现的非聚合函数字段,必须出现在 GROUP BY 中(比如上面的 u.username 必须加在 GROUP BY 里)。
别名使用:GROUP BY 不能用查询别名(如 GROUP BY 商品分类 错误),但 ORDER BY 可以。
NULL 值处理:分组时,NULL 值会被归为一组(比如无订单的用户 wangwu,统计结果为 NULL)。
性能优化:分组前用 WHERE 过滤掉无关数据,减少分组计算量(比如先过滤价格 > 100 的商品)。
总结
GROUP BY 是分组查询的核心,单字段分组适合基础统计,多字段分组适合细粒度统计。
WHERE 过滤原始数据行,HAVING 过滤分组结果,两者结合能精准筛选统计范围。
实战中常结合「联表 + 分组 + 排序」,实现复杂的业务统计(如用户消费分析、商品分类统计)。
进阶6:多表连接查询
笛卡尔乘积:如果连接条件省略或无效则会出现
解决办法:添加上连接条件
一、传统模式下的连接 :(内连接)
等值连接------非等值连接
1.等值连接的结果 = 多个表的交集
2.n表连接,至少需要n-1个连接条件
3.多个表不分主次,没有顺序要求
4.一般为表起别名,提高阅读性和性能
二、sql语法:通过join关键字实现连接
mysql
含义:1999年推出的sql语法
支持:
等值连接、非等值连接 (内连接)
外连接
交叉连接
语法:
select 字段,...
from 表1
【inner|left outer|right outer|cross】join 表2 on 连接条件
【inner|left outer|right outer|cross】join 表3 on 连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
好处:语句上,连接条件和筛选条件实现了分离,简洁明了!
-- 左连接
-- 3. 四表左连接:查询所有用户+所有订单+订单明细+商品信息
SELECT
u.username AS 用户名,
o.order_id AS 订单ID,
p.product_name AS 商品名称,
oi.quantity AS 购买数量
FROM user_info u
LEFT JOIN order_main o ON u.user_id = o.user_id
LEFT JOIN order_item oi ON o.order_id = oi.order_id
LEFT JOIN product p ON oi.product_id = p.product_id;
-- 运行结果(wangwu无订单,对应字段为NULL):
-- 用户名 | 订单ID | 商品名称 | 购买数量
-- zhangsan | 1 | 小米14手机 | 1
-- zhangsan | 1 | 罗技机械键盘 | 1
-- zhangsan | 3 | 金士顿U盘128G | 1
-- lisi | 2 | 苹果iPad Pro | 1
-- wangwu | NULL | NULL | NULL
-- 右连接
-- 1. 基础右连接:查询所有订单+对应的用户(等价于用户表左连接订单表)
SELECT
o.order_id AS 订单ID,
u.username AS 用户名,
o.order_amount AS 订单金额
FROM user_info u
RIGHT JOIN order_main o
ON u.user_id = o.user_id;
-- 运行结果(和内连接结果一致,因为所有订单都有对应的用户):
-- 订单ID | 用户名 | 订单金额
-- 1 | zhangsan | 5298.00
-- 2 | lisi | 7999.00
-- 3 | zhangsan | 89.00
三、自连接
案例:查询员工名和直接上级的名称
sql
mysql
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m ON e.`manager_id`=m.`employee_id`;
-- 自连接查询:每个用户+对应的推荐人名称
SELECT
u1.user_id AS 用户ID,
u1.username AS 用户名,
u2.username AS 推荐人名称 -- 自连接的表别名u2代表推荐人
FROM user_info u1
LEFT JOIN user_info u2
ON u1.referrer_id = u2.user_id; -- 关联条件:推荐人ID=用户ID
-- 运行结果:
-- 用户ID | 用户名 | 推荐人名称
-- 1 | zhangsan | NULL (无推荐人)
-- 2 | lisi | zhangsan
-- 3 | wangwu | lisi
sql
mysql
SELECT e.last_name,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;
进阶7:子查询
含义:
mysql
一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询
在外面的查询语句,称为主查询或外查询
特点:
子查询别名:表子查询(返回多行多列)必须起别名(如 t),否则 MySQL 报错;!!!
mysql
1、子查询都放在小括号内
2、子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧
3、子查询优先于主查询执行,主查询使用了子查询的执行结果
4、子查询根据查询结果的行数不同分为以下两类:
① 单行子查询
结果集只有一行
一般搭配单行操作符使用:> < = <> >= <=
非法使用子查询的情况:
a、子查询的结果为一组值
b、子查询的结果为空
② 多行子查询
结果集有多行
一般搭配多行操作符使用:any、all、in、not in
in: 属于子查询结果中的任意一个就行
any和all往往可以用其他查询代替
-- any 和 all的应用
-- 3. 查询「订单金额大于任意一个已完成订单金额」的订单(ANY)
SELECT order_id, order_amount
FROM order_main
WHERE order_amount > ANY (
-- 子查询:查所有已完成订单的金额(返回列:89.00)
SELECT order_amount FROM order_main WHERE order_status = 3
);
-- 运行结果(金额>89.00的订单):
-- order_id | order_amount
-- 1 | 5298.00
-- 2 | 7999.00
-- 补充:ALL 表示「大于所有」,比如 > ALL (SELECT ...) 会只返回7999.00的订单
-- 行子查询
-- 2. 查询「每个用户的最大金额订单」(行子查询+分组)
SELECT
order_id AS 订单ID,
user_id AS 用户ID,
order_amount AS 订单金额
FROM order_main o1
WHERE (user_id, order_amount) IN (
-- 子查询:按用户分组,查每个用户的最大金额(返回多行两列)
SELECT user_id, MAX(order_amount) FROM order_main GROUP BY user_id
);
-- 运行结果:
-- 订单ID | 用户ID | 订单金额
-- 1 | 1 | 5298.00
-- 2 | 2 | 7999.00
-- 表子查询
-- 1. 查询「订单金额>5000」的订单+对应的用户信息(子查询作为数据源)
SELECT
t.order_id AS 订单ID,
u.username AS 用户名,
t.order_amount AS 订单金额
FROM (
-- 子查询:筛选金额>5000的订单(返回多行多列的临时表)
SELECT order_id, user_id, order_amount FROM order_main WHERE order_amount > 5000
) t -- 给子查询起别名t
JOIN user_info u ON t.user_id = u.user_id; -- 临时表关联用户表
-- 运行结果:
-- 订单ID | 用户名 | 订单金额
-- 1 | zhangsan | 5298.00
-- 2 | lisi | 7999.00
-- 关联子查询
-- 1. 查询「每个用户的最大金额订单」(关联子查询)
SELECT
o1.order_id AS 订单ID,
o1.user_id AS 用户ID,
o1.order_amount AS 订单金额
FROM order_main o1
WHERE o1.order_amount = (
-- 子查询:查当前用户(o1.user_id)的最大订单金额(依赖外层字段)
SELECT MAX(o2.order_amount) FROM order_main o2 WHERE o2.user_id = o1.user_id
);
-- 运行结果:
-- 订单ID | 用户ID | 订单金额
-- 1 | 1 | 5298.00
-- 2 | 2 | 7999.00
进阶8:分页查询
应用场景:
实际的web项目中需要根据用户的需求提交对应的分页查询的sql语句
语法:
mysql
select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 【起始的条目索引,】条目数;
特点:
mysql
1.起始条目索引从0开始
2.limit子句放在查询语句的最后
3.公式:select * from 表 limit (page-1)*sizePerPage,sizePerPage
假如:
每页显示条目数sizePerPage
要显示的页数 page
分页查询优化技巧:
1、基于主键/索引排序分页(推荐)
mysql
-- 优化:用主键(product_id)排序,避免全表扫描
-- 场景:商品表大偏移量分页(模拟第100页,每页10条)
SELECT
product_id AS 商品ID,
product_name AS 商品名称,
price AS 价格
FROM product
WHERE product_id > (100-1)*10 -- 偏移量转换为主键筛选:(页码-1)*条数
ORDER BY product_id ASC
LIMIT 10; -- 只取10条,无需大偏移量
2、避免select,只查询必要字段*
mysql
-- 反例:SELECT * 会查所有字段,性能差
SELECT * FROM product LIMIT 10000, 10;
-- 正例:只查需要的字段,减少数据传输
SELECT product_id, product_name, price FROM product
ORDER BY product_id ASC LIMIT 10000, 10;
3、先分页再分表(减少联表数据量)
应用场景:
某电商平台的后台管理系统,有一个「订单列表」功能:
- 运营人员需要查看订单信息,每页显示 20 条;
- 订单表(
order_main)有1000 万条历史数据,且每天新增 10 万 + 订单; - 列表需要展示的字段:订单 ID、下单用户昵称、订单金额、支付状态、商品名称、收货人电话(这些字段分布在
order_main、user_info、order_item、product、user_address5 张表中)。
mysql
-- 优化:先对主表分页,再联表查询详情(适合大表)
SELECT
o.order_id, u.username, o.order_amount
FROM (
-- 子查询:先对订单表分页(只查主键)
SELECT order_id, user_id, order_amount
FROM order_main
ORDER BY order_id ASC
LIMIT 0, 2 -- 第1页,每页2条
) o
JOIN user_info u ON o.user_id = u.user_id; -- 再联表查用户名
关键注意事项
- 分页必须排序 :如果不加
ORDER BY,MySQL 返回的是「随机结果」,分页翻页会出现数据重复 / 缺失; - 偏移量计算:偏移量 = (页码 - 1) × 每页条数(比如第 3 页、每页 10 条 → 偏移量 = 20);
- 大偏移量优化 :避免直接用
LIMIT 10000, 10,优先用「主键 / 索引筛选 + LIMIT 条数」;
分页查询关键说明:
- 主键
product_id是自增的,第 1000 页的起始主键值 = 偏移量(9990); - 如果主键不是从 1 开始,或有删除数据导致主键不连续,可先查「上一页最后一条的主键」:
mysql
-- ❶ 传统低效写法(不推荐):大偏移量导致全表扫描
SELECT
product_id, product_name, price, stock
FROM product
ORDER BY product_id ASC -- 必须按主键排序(和筛选条件一致)
LIMIT 9990, 10; -- 第1000页,每页10条 → 偏移量9990
-- ❷ 优化写法(推荐):主键筛选 + LIMIT 条数
SELECT
product_id, product_name, price, stock
FROM product
WHERE product_id > 9990 -- 直接定位到起始主键(偏移量=9990)
ORDER BY product_id ASC -- 按主键排序(保证有序)
LIMIT 10; -- 只取10条,无需大偏移量
- NULL 值处理 :左连接分页时,用
IFNULL()替换 NULL(如IFNULL(SUM(amount), 0))。
sql查询优化:
1、按需查询字段,减少网络IO消耗
2、避免使用select*,减少Mysql优化器负担
3、查询的字段尽量保证索引覆盖
4、借助nosql缓存数据环节Mysql数据库的压力
进阶9:联合查询
引入:
union 联合、合并
union all 不会去重, union会自动去重
语法:
mysql
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
-- ❶ UNION ALL(不查重,性能高):合并高价商品(>5000)和高库存商品(>200)
SELECT
product_id AS 商品ID,
product_name AS 商品名称,
price AS 价格,
stock AS 库存,
'高价商品' AS 标签 -- 自定义标签,区分数据来源
FROM product
WHERE price > 5000
UNION ALL -- 合并第二个查询结果
SELECT
product_id AS 商品ID,
product_name AS 商品名称,
price AS 价格,
stock AS 库存,
'高库存商品' AS 标签
FROM product
WHERE stock >= 200;
-- 运行结果(包含重复记录:苹果iPad Pro既高价又高库存?不,库存50<200,所以无重复):
-- 商品ID | 商品名称 | 价格 | 库存 | 标签
-- 2 | 华为Mate60 | 5999.00 | 80 | 高价商品
-- 3 | 苹果iPad Pro | 7999.00 | 50 | 高价商品
-- 4 | 罗技机械键盘 | 299.00 | 200 | 高库存商品(注:stock=200不满足>200)
-- 5 | 金士顿U盘 | 89.00 | 500 | 高库存商品
-- ❷ UNION(自动去重):如果有重复记录会被删除
-- 模拟场景:修改数据让某商品同时满足两个条件,再用UNION
UPDATE product SET stock = 600 WHERE product_id = 3; -- 苹果iPad Pro库存改为600
SELECT product_id, product_name, price, stock, '高价商品' AS 标签
FROM product WHERE price > 5000
UNION -- 去重,苹果iPad Pro只出现一次
SELECT product_id, product_name, price, stock, '高库存商品' AS 标签
FROM product WHERE stock > 200;
-- 运行结果(苹果iPad Pro只显示一条,标签为第一个查询的「高价商品」):
-- 商品ID | 商品名称 | 价格 | 库存 | 标签
-- 2 | 华为Mate60 | 5999.00 | 80 | 高价商品
-- 3 | 苹果iPad Pro | 7999.00 | 600 | 高价商品
-- 5 | 金士顿U盘 | 89.00 | 500 | 高库存商品
-- 恢复数据
UPDATE product SET stock = 50 WHERE product_id = 3;
综合案例:
mysql
SELECT * FROM (
-- 子查询:联合查询结果(临时表)
SELECT
product_id, product_name, price, stock, '高价商品' AS 标签
FROM product WHERE price > 5000
UNION ALL
SELECT
product_id, product_name, price, stock, '高库存商品' AS 标签
FROM product WHERE stock > 200
) t -- 给临时表起别名
ORDER BY price DESC -- 先排序
LIMIT 0, 2; -- 再分页:第1页,每页2条
-- 运行结果:
-- product_id | product_name | price | stock | 标签
-- 3 | 苹果iPad Pro | 7999.00 | 50 | 高价商品
-- 2 | 华为Mate60 | 5999.00 | 80 | 高价商品
特点:
mysql
1、多条查询语句的查询的列数必须是一致的
2、多条查询语句的查询的列的类型几乎相同
3、union代表去重,union all代表不去重
SQL 完整执行顺序
当一条 SQL 同时包含 WHERE/GROUP BY/HAVING/ORDER BY 时,执行顺序是固定的:
FROM/JOIN:确定要查询的表和关联关系(先找到数据源)。WHERE:过滤原始数据行(分组前筛选)。GROUP BY:将过滤后的行分组聚合。HAVING:过滤分组后的统计结果(分组后筛选)。SELECT:确定要展示的字段(包括聚合函数结果、别名)。ORDER BY:对最终的统计结果行排序(最后执行)。
mysql
SELECT
category,
SUM(stock) AS total_stock
FROM product
WHERE price > 100 -- 步骤2:过滤掉U盘(89)
GROUP BY category -- 步骤3:聚合为3个分组(手机、平板、外设)
HAVING SUM(stock) > 100 -- 步骤4:过滤掉平板(50)
ORDER BY total_stock DESC; -- 步骤6:对手机、外设排序
DML语言
插入
语法:
insert into 表名(字段名,...)
values(值1,...);
特点:
mysql
1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致
5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
字段和值的「数量、顺序、类型」必须匹配
-- ✅ 正确写法1:指定字段,值和字段一一对应
INSERT INTO user_info (user_id, username, phone, create_time)
VALUES (4, 'zhaoliu', '13700137000', NOW());
-- ✅ 正确:字符串/日期用单引号
INSERT INTO product (product_id, product_name, price, create_time)
VALUES (6, '华为Pura70', 4499.00, '2026-01-22 10:30:00');
-- 处理特殊字符
-- 转义单引号
INSERT INTO product (product_name) VALUES ('O\'Neil的手机'); -- 方法1:\转义
使用IGNORE关键字,避免插入重复数据
-- ✅ 重复则忽略
INSERT IGNORE INTO user_info (user_id, username)
VALUES (1, 'zhangsan'); -- user_id=1已存在,不会报错,仅跳过
修改
修改单表语法:
mysql
update 表名 set 字段=新值,字段=新值
【where 条件】
修改多表语法:
mysql
update 表1 别名1,表2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件
批量修改
-- ✅ 分批更新示例(伪代码,结合编程语言执行)
-- 第1批:更新product_id 1-1000的商品
UPDATE product
SET price = price * 0.9 -- 打9折
WHERE product_id BETWEEN 1 AND 1000;
-- 第2批:更新product_id 1001-2000的商品
UPDATE product
SET price = price * 0.9
WHERE product_id BETWEEN 1001 AND 2000;
条件更新
-- ✅ 条件更新:手机类商品降价100,平板类降价200,其他不变
UPDATE product
SET price = CASE
WHEN category = '手机' THEN price - 100
WHEN category = '平板' THEN price - 200
ELSE price -- 其他分类不更新
END
WHERE category IN ('手机', '平板'); -- 只筛选需要更新的分类
删除
方式1:delete语句
单表的删除: ★
delete from 表名 【where 筛选条件】
删除注意事项:
mysql
核心定义:
DROP TABLE 表名 是「删除整张表」的操作,数据、表结构、索引、约束、触发器等全部删除,操作不可恢复(除非有备份),属于极高危操作。
数据 + 结构全删除(表从数据库中消失,无法再操作);
速度最快(直接删除表的元数据);
不可回滚,无任何恢复可能(除非从备份恢复);
可加 IF EXISTS 避免表不存在时报错(推荐);
需 DROP 权限,生产环境需严格管控。
-- 2. 开启事务(确保可回滚)
START TRANSACTION;
-- 3. 执行DELETE,确认无误后再提交
DELETE FROM product WHERE product_id = 6;
-- COMMIT; -- 确认正确再提交
-- ROLLBACK; -- 出错直接回滚(数据恢复)
多表的删除:
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;
方式2:truncate语句
mysql
truncate table 表名
核心定义:
TRUNCATE TABLE 表名 是「清空表数据」的操作,仅删除表中所有行,表结构、索引、约束等全部保留,且操作不可回滚(非事务安全)。
只删数据,不删表结构(表还在,可继续插入数据);
速度极快(不记录单行删除日志,直接重置表);
会重置自增主键(比如主键 ID 从 1 重新开始);
无法加 WHERE 条件(只能清空全表,不能删指定行);
非事务安全(执行后无法通过 ROLLBACK 回滚);
需 DROP 权限(和 DROP 权限相同)。
两种方式的区别【面试题】
mysql
#1.truncate不能加where条件,而delete可以加where条件
#2.truncate的效率高一丢丢
#3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始
#delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始
#4.truncate删除不能回滚,delete删除可以回滚
DDL语句
库和表的管理
库的管理:
mysql
一、创建库
create database 库名
二、删除库
drop database 库名
表的管理:
- 创建表
mysql
CREATE TABLE IF NOT EXISTS stuinfo(
stuId INT,
stuName VARCHAR(20),
gender CHAR,
bornDate DATETIME
);
DESC studentinfo;
# 2.修改表 alter
语法:ALTER TABLE 表名 ADD|MODIFY|DROP|CHANGE COLUMN 字段名 【字段类型】;
#①修改字段名
ALTER TABLE studentinfo CHANGE COLUMN sex gender CHAR;
mysql
#②修改表名
ALTER TABLE stuinfo RENAME [TO] studentinfo;
#③修改字段类型和列级约束
ALTER TABLE studentinfo MODIFY COLUMN borndate DATE ;
#④添加字段
ALTER TABLE studentinfo ADD COLUMN email VARCHAR(20) first;
#⑤删除字段
ALTER TABLE studentinfo DROP COLUMN email;
删除表
DROP TABLE [IF EXISTS] studentinfo;
mysql
-- 场景2:批量删除字段(一次性删除多个无用字段)
ALTER TABLE product
DROP COLUMN temp_tag,
DROP COLUMN unused_field;
mysql
添加索引:
-- 场景1:给product表的product_name添加普通索引(优化按名称查询)
ALTER TABLE product
ADD INDEX idx_product_name (product_name);
-- 场景2:给user_info表的phone添加唯一索引(保证手机号不重复)
ALTER TABLE user_info
ADD UNIQUE INDEX uk_user_phone (phone);
-- 场景3:给order_item表添加联合索引(优化订单+商品的关联查询)
ALTER TABLE order_item
ADD INDEX idx_order_product (order_id, product_id);
-- 场景4:给无主键的表添加主键(如order_item表,假设item_id未设主键)
ALTER TABLE order_item
ADD PRIMARY KEY (item_id);
常见类型
mysql
整型:
tinyint smallint int/integer bigint
无负数的场景加unsigned扩大取值范围
小数:
浮点型 float(单精度浮点数约7位精度) double(双精度浮点约15位精准)
定点型 decimal(M,D) 金额,价格
字符型: char varchar text(大文本,无需指定长度,最大长度位65535字符) longtext(超大文本,最大4个G)
日期型:
Bool类型:bool,boolean
| 类型 | 存储空间(字节) | 格式 | 精度 | 典型用途 |
|---|---|---|---|---|
| date | 3 | YYYY-MM-DD | 日期 | 生日、下单日期 |
| time | 3 | HH:MM:SS | 时间 | 配送时间、活动时段 |
| datetime | 8 | YYYY-MM-DD HH:MM:SS | 秒级 | 创建时间、更新时间 |
| timestamp | 4 | YYYY-MM-DD HH:MM:SS | 秒级 | 时间戳(自动更新) |
| datetime(6) | 8 | YYYY-MM-DD HH:MM:SS.ffffff | 微秒级 | 精准时间(支付时间、日志) |
常见约束
mysql
NOT NULL
DEFAULT
UNIQUE
CHECK
PRIMARY KEY
FOREIGN KEY
check应用:
mysql
CREATE TABLE product (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL,
-- 单个字段CHECK:价格必须≥0
CONSTRAINT chk_product_price CHECK (price >= 0),
-- 单个字段CHECK:库存必须≥0
CONSTRAINT chk_product_stock CHECK (stock >= 0),
-- 多字段联合CHECK:价格>0时库存不能为0(避免「有价格无库存」)
CONSTRAINT chk_product_price_stock CHECK (price = 0 OR stock > 0)
);
索引分类:
普通索引:
最基础的索引类型,没有任何限制,仅用于加速查询,允许索引列的值重复和为空。
唯一索引:
索引列的值必须是唯一的,但允许有空值(注意:如果是多个列的联合唯一索引,只要组合值唯一即可)。常用于保证数据唯一性,如用户手机号、邮箱。
主键索引:
特殊的唯一索引,不允许有空值,一张表只能有一个主键索引,用于唯一标识表中的每一行数据。InnoDB 引擎中,主键索引是聚簇索引的基础。
复合索引(联合索引):
适合两列同时作为where的条件场景。
遵循最左前缀法则:如果创建的是联合索引,就要遵循该法则,使用索引时,where后面的条件需要从索引的最左前列开始使用,并且不能跳过索引列中的列使用。
即使条件顺序颠倒,MySQL优化器会调整,仍生效
场景1:按照索引字段顺序使用,三个字段都使用了索引,没有问题。
场景2:直接跳过user_name使用索引字段,索引无效,未使用到索引。
场景3:不按照创建联合索引的顺序,使用索引
mysql
-- 1. 命中索引(使用最左列age)
SELECT * FROM user WHERE age = 25;
-- 2. 命中索引(使用age+gender,完整匹配)
SELECT * FROM user WHERE age = 25 AND gender = '男';
-- 3. 命中索引(即使条件顺序颠倒,MySQL优化器会调整,仍生效)
SELECT * FROM user WHERE gender = '男' AND age = 25;
-- 4. 未命中索引(跳过左列age,仅查gender)
SELECT * FROM user WHERE gender = '男';
全文索引:
专门用于对文本内容(如文章、评论)进行全文检索,仅支持 CHAR、VARCHAR、TEXT 类型,MyISAM 和 InnoDB(5.6+)引擎支持。
查询操作在数据量比较少时,可以使用like模糊查询,但是对于大量的文本数据检索,效率很低。如果使用全文索引,查询速度会比like快很多倍。
空间索引:
用于存储地理空间数据(如点、线、面),仅支持 GEOMETRY 等空间数据类型,MyISAM 和 InnoDB(5.7+)引擎支持,且索引列不能为空。
其他维度索引划分:
数据结构划分:B+树索引,哈希索引,R树索引
物理存储划分:聚簇索引,非聚簇索引
索引数量划分:单列索引,联合索引(复合索引)
constraint foreign key references
数据库事务
只有增删改查有事务之说
特点
(ACID)
原子性:要么都执行,要么都回滚
一致性:保证数据的状态操作前和操作后保持一致
隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰
持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改
事务的分类:
隐式事务,没有明显的开启和结束事务的标志
mysql
比如
insert、update、delete语句本身就是一个事务
显式事务,具有明显的开启和结束事务的标志
mysql
1、开启事务
取消自动提交事务的功能
2、编写事务的一组逻辑操作单元(多条sql语句)
insert
update
delete
3、提交事务或回滚事务
使用到的关键字
mysql
set autocommit=0;
start transaction;
commit;
rollback;
savepoint 断点
commit to 断点
rollback to 断点
set autocommit=0
delete from account where id =25;
savepoint a; # 设置保存点
delete from account where id =28;
rollback to a;# 回滚到保存点
事务的隔离级别:
事务并发问题如何发生?
当多个事务同时操作同一个数据库的相同数据时
事务的并发问题有哪些?
脏读:一个事务读取到了另外一个事务未提交的数据
不可重复读:同一个事务中,多次读取到的数据不一致
幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据
如何避免事务的并发问题?
mysql
通过设置事务的隔离级别
1、READ UNCOMMITTED
2、READ COMMITTED 可以避免脏读(oracle数据库的事务隔离级别)
3、REPEATABLE READ 可以避免脏读、不可重复读和一部分幻读(mysql的事务隔离级别)
4、SERIALIZABLE可以避免脏读、不可重复读和幻读
设置隔离级别:
mysql
set session|global transaction isolation level 隔离级别名;
查看隔离级别:
mysql
select @@tx_isolation;
视图
含义:理解成一张虚拟的表
视图和表的区别:
使用方式 占用物理空间
mysql
视图 完全相同 不占用,仅仅保存的是sql逻辑
表 完全相同 占用
视图的好处:
mysql
1、sql语句提高重用性,效率高
2、和表实现了分离,提高了安全性
视图的创建
语法:
CREATE VIEW 视图名
AS
查询语句;
mysql
create view v1 as
SELECT order_id, order_amount, order_amount / 100 AS amount_div_100
FROM order_main
ORDER BY amount_div_100;
select * from v1;
视图的增删改查
1、查看视图的数据 ★
mysql
SELECT * FROM my_v4;
SELECT * FROM my_v1 WHERE last_name='Partners';
2、插入视图的数据
INSERT INTO my_v4(last_name,department_id) VALUES('虚竹',90);
3、修改视图的数据
UPDATE my_v4 SET last_name ='梦姑' WHERE last_name='虚竹';
4、删除视图的数据
DELETE FROM my_v4;
某些视图不能更新
包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all
常量视图
Select中包含子查询
join
from一个不能更新的视图
where子句的子查询引用了from子句中的表
视图逻辑的更新
mysql
# 方式一:
CREATE OR REPLACE VIEW test_v7
AS
SELECT last_name FROM employees
WHERE employee_id>100;
mysql
#方式二:
ALTER VIEW test_v7
AS
SELECT employee_id FROM employees;
SELECT * FROM test_v7;
视图的删除
mysql
DROP VIEW test_v1,test_v2,test_v3;
视图结构的查看
mysql
DESC test_v7;
SHOW CREATE VIEW test_v7;
视图与表对比:
| 创建语法 | 是否实际占用物理空间 | 使用 | |
|---|---|---|---|
| 视图 | create view | 只是保存了sql逻辑 | 增删改查,一般不能增删改 |
| 表 | create table | 保存数据 | 增删改查 |
存储过程
含义:一组经过预先编译的sql语句的集合
好处:
mysql
1、提高了sql语句的重用性,减少了开发程序员的压力
2、提高了效率
3、减少了传输次数
分类:
mysql
1、无返回无参
2、仅仅带in类型,无返回有参
3、仅仅带out类型,有返回无参
4、既带in又带out,有返回有参
5、带inout,有返回有参
注意:in、out、inout都可以在一个存储过程中带多个
创建存储过程
语法:
mysql
create procedure 存储过程名(in|out|inout 参数名 参数类型,...)
begin
存储过程体
end
类似于方法:
mysql
修饰符 返回类型 方法名(参数类型 参数名,...){
方法体;
}
注意
mysql
1、需要设置新的结束标记
delimiter 新的结束标记
示例:
delimiter $
CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
BEGIN
sql语句1;
sql语句2;
END $
2、存储过程体中可以有多条sql语句,如果仅仅一条sql语句,则可以省略begin end
3、参数前面的符号的意思
in:该参数只能作为输入 (该参数不能做返回值)
out:该参数只能作为输出(该参数只能做返回值)
inout:既能做输入又能做输出
调用存储过程
call 存储过程名(实参列表)
函数
创建函数
学过的函数:LENGTH、SUBSTR、CONCAT等
语法:
mysql
CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回类型
BEGIN
函数体
END
调用函数
SELECT 函数名(实参列表)
函数和存储过程的区别
mysql
关键字 调用语法 返回值 应用场景
函数 FUNCTION SELECT 函数() 只能是一个 一般用于查询结果为一个值并返回时,当有返回值而且仅仅一个
存储过程 PROCEDURE CALL 存储过程() 可以有0个或多个 一般用于更新
流程控制结构
系统变量
一、全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启
mysql
查看所有全局变量
SHOW GLOBAL VARIABLES;
查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
查看指定的系统变量的值
SELECT @@global.autocommit;
为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
二、会话变量
作用域:针对于当前会话(连接)有效
mysql
查看所有会话变量
SHOW SESSION VARIABLES;
查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';
自定义变量
一、用户变量
声明并初始化:
mysql
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
赋值:
mysql
方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;
mysql
方式二:一般用于赋表 中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;
使用:
mysql
select @变量名;
二、局部变量
声明:
declare 变量名 类型 【default 值】;
赋值:
mysql
方式一:一般用于赋简单的值
SET 变量名=值;
SET 变量名:=值;
SELECT 变量名:=值;
mysql
方式二:一般用于赋表中的字段值
SELECT 字段名或表达式 INTO 变量
FROM 表;
使用:
mysql
select 变量名
二者的区别:
mysql
作用域 定义位置 语法
用户变量 当前会话的任何地方 加@符号,不用指定类型
局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型
分支
一、if函数
语法:if(条件,值1,值2)
特点:可以用在任何位置
二、case语句
语法:
mysql
情况一:类似于switch
case 表达式
when 值1 then 结果1或语句1(如果是语句,需要加分号)
when 值2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)
情况二:类似于多重if
case
when 条件1 then 结果1或语句1(如果是语句,需要加分号)
when 条件2 then 结果2或语句2(如果是语句,需要加分号)
...
else 结果n或语句n(如果是语句,需要加分号)
end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要)
特点:
可以用在任何位置
三、if elseif语句
语法:
mysql
if 情况1 then 语句1;
elseif 情况2 then 语句2;
...
else 语句n;
end if;
特点:
只能用在begin end中!!!!!!!!!!!!!!!
三者比较: 应用场合
if函数 简单双分支
case结构 等值判断 的多分支
if结构 区间判断 的多分支
循环
语法:
mysql
【标签:】WHILE 循环条件 DO
循环体
END WHILE 【标签】;
特点:
mysql
只能放在BEGIN END里面
如果要搭配leave跳转语句,需要使用标签,否则可以不用标签
leave类似于java中的break语句,跳出所在循环!!!