2025-03-29 16:55:07 +08:00

467 lines
9.8 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MySQL
[MySQL 教程 | 菜鸟教程](https://www.runoob.com/mysql/mysql-tutorial.html)
## docker 安装mysql
1. 创建 docker-compose.yml
```sh
vim docker-comopse.yml
===
services:
mysql:
image: mysql
restart: on-failure
environment:
- MYSQL_ROOT_PASSWORD=Aa123456
- MYSQL_DATABASE=mybase
- MYSQL_USER=hxx
- MYSQL_PASSWORD=Aa123456
- TZ=Asia/Shanghai
- character-set-server=utf8mb4
- collation-server=utf8mb4_unicode_ci
ports:
- '3307:3306'
volumes:
- ./data:/var/lib/mysql # 数据挂载
- ./init:/docker-entrypoit-initdb.d/ # 初始脚本
===
```
2. 创建授权 root 用户可以远程链接的脚本
```sh
mkdir init
vim init/remote.sql
===
-- GRANT ALL privileges on *.* TO 'root'@'%';
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native-pasword BY 'Aa123456';
===
```
* 错误
Client does not support authentication protocol requested by server; consider upgrading MySQL client
```sh
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';
# ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY '你的密码';
flush privileges;
# mysq> 加一个闪烁的光标等待命令的输入, 输入 exit 或 quit 退出登录
```
## 语法
* 大小写不敏感
* 可以单行/多行, 以`;`结束
* 注释
* 单行: `-- 注释内容`
* 单行: `# 注释内容`
* 多行: `/* 多行内容 */`
## 数据库操作
```mysql
# 查看数据库
show databases;
# 使用数据库
use 数据库名;
# 创建数据库
create database 数据库名 [charset utf8];
# 删除数据库
drop database 数据库名;
# 查看当前使用的数据库
select database();
```
## 表操作
### 查
```mysql
# 查看有哪写表, 需要先选择库
show tables;
# 查看表的结构
desc 表名;
```
### 增
```mysql
# 创建表
create table 表名称(
列名称 列类型,
列名称 列类型,
......
);
/*
列类型有:
int 整数
float 浮点数
varchar(长度) 文件,长度为数字, 做最大长度限制
date 日期类型
timestamp 时间戳
*/
# 复制表结构
create table 新表名 like 旧表名;
# 复制表
create table 新表名 as (select * from 旧表名);
```
**通用字段**
* id
* create_time
* creator
* update_time: 默认值可以为 CURRENT_TIMESTAMP
* update_by
* remark
一张表的字段不宜超过20个,超过考虑拆分
### 删
```mysql
# 删除表
drop table 表名称;
drop table if exists 表名称;
```
### 改
```mysql
# 增加字段
alter table 表名 add 字段名 类型;
# 删除字段
alter table 表名 drop 字段名;
# 更改字段类型
alter table 表名 modify 字段 类型;
# 更改字段名
alter table 表名 change 旧字段 新字段 类型;
```
## 增删改查
### 增
```mysql
insert into 表名 [(字段列表)] values (值列表);
-- 如果为所有字段新增数据, 不需要写字段列表
-- null 说明由系统自动生成标识列
-- 如果字段非空, 但有默认值, 可以不赋值
-- 非空字段, 没有默认值, 一定要赋值
-- 字符串一定要加引号, 数字可加可不加
```
```mysql
insert into users values (null, '马九', 22, '男', '马家村', 0);
-- 或者
insert into users (name, age, address) values ('马十', 21, '马家村');
# 插入多条
insert into 表名 [(字段列表)] values (值列表), (值列表), ...;
```
### 删
```mysql
delete from 表名 where 条件;
# 清空表
delete from 表名;
```
```mysql
DELETE from users where name = '马十';
DELETE from users where id in (1, 3);
```
### 改
```mysql
updata 表名 set 字段 = 新值, 字段 = 新值 where 条件;
-- 一定要加上条件, 不加条件所有的都被修改了
```
```mysql
update users set age = 20 where id = 2;
-- 使用表达式
update users set age = age + 1 where id = 1;
```
```mysql
UPDATE torrent
SET url = REPLACE(url, 'mikanani.me', 'mikanime.tv')
WHERE url LIKE '%mikanani.me%';
```
### 查
```mysql
-- 注释为双横线加空格
select 字段 from 表名 [where 条件];
-- 条件没有可以不写
-- 返回的结果是虚拟表
-- 在sql中. 逻辑等和赋值都是用=号
-- 逻辑与 and
-- 逻辑或 or
-- 逻辑非 not
```
```mysql
select * from users;
select id, name, gender from users;
select * from users where id = 2;
select * frm users where id = 2 or id = 3;
select * from users where gender = '男' and age > 20;
select * from users where id in (2, 3, 4, 5); -- id在2, 3, 4, 5 范围内
select * from users where id not in (1, 2); -- id 不包括2, 3, 4, 5
```
## 其他常用函数
### 统计
```mysql
-- 统计所有数据条数
select count(*) from users;
-- 只统计非空的数据调数, 过滤null
select count(gender) from users;
-- 查询最大
select max(age) from users;
-- 查询最小
select min(age) from users;
-- 求平均, 数值有效
select avg(age) from users;
```
### 排序
```mysql
-- asc升序, 默认升序可以不写, desc倒序
select * from users order by id [asc];
select * from users order by id desc;
```
```mysql
# 排序
select 列|聚合函数|* from 表
[where 条件]
[group by 列]
order by 列
[asc|desc];
# asc 升序, 默认, 可以不写
# desc 倒序
```
### 分页
```mysql
select * from users limit m; -- 前m条
select * from users limit m, n; -- 查询m+n条记录去掉前m条返回后n条记录.m的值越大查询的性能会越低
select * from users limit 3 offset 0; -- 从第1条开始, 向下查询3条
-- offset 偏移
-- 当m非常大时, 要先查询m+n条记录 , 再取n条, 非常慢, 可以进行优化
select * from users limit 10000, 100;
-- 优化思想, 先定位id
select * from users where id >100001 limit 100;
```
```mysql
# 分页查询
select 列|聚合函数|* from 表
[where 条件]
[group by 列]
order by 列
[asc|desc]
limit n[,m];
# 只有n, 取n条
# n, m 跳过n条, 取m条
```
### 分组聚合
```mysql
# 分组聚合
select 字段|聚合函数 from 表名 [where 条件] group by 列;
# group by 出现的哪个列, 只有这个列能用在字段中
# 按照 group by后面的条件进行分组
/*
聚合函数有:
sum(列) 求和
avg(列) 平均
min(列) 最小
max(列) 最大
count(列|*) 数量
*/
# 按男女分组, 统计平均年龄
select gender, avg(age) from student group by gender;
# 数值函数
# 四舍五入: round()
# 向上取整: ceil()
# 向下取整: floor()
# 按部门求平均工资, 并且过滤出工资大于3000的
select depnum, ave(salary) as 平均工资 from emp group by depnum having 平均工资>3000;
# HAVING 子句用于对分组结果进行过滤。它通常与 GROUP BY 子句一起使用,用于筛选聚合函数的结果。
# WHERE 子句用于在分组前对记录进行过滤
# as 命名
```
**注意事项:**
* select, from 必写
* where, group by, order by, limit 按须
* 执行顺序: from -> where -> group by 和聚合函数 -> select -> order by -> limit
### 去重
```mysql
# 从表中选择不重复的列
SELECT DISTINCT 字段 FROM 表名;
# 多列,并且这些列的组合是唯一
SELECT DISTINCT column1, column2 FROM table_name;
```
### 模糊查询
```mysql
# like
# % 表示匹配多个字符
# _ 表示匹配单个字符
select * from 表名 where 字段 like '%字符%';
```
### 长度
```mysql
# 判断字符长度
select length('一');
# 获取姓名为两个中文的
SELECT * FROM users WHERE LENGTH(name)=6;
```
### 运算符
```mysql
# select 后面 + - * /
# 应用在数值类型
# 查询员工半年的工资
select name, salary*6 as 半年工资 from emp;
# ifnull(要检查的表达式, 为null时的替代值)
select name, (salary+ifnull(comm,0))*6 as 半年工资(加奖金) from emp;
```
### 日期函数
```mysql
select month('2024-01-01');
select year('2024-01-01');
select day('2024-01-01');
select week('2024-01-01');
select now(); # 当前时间
# timestampdiff(格式, 开始时间, 结束时间)
SELECT timestampdiff(DAY, '2024-01-01', NOW());
```
### 多表查询
![](https://img.081024.xyz/6-MySQL-20240601234301884.jpg)
#### 交叉连接/关联查询
速度比较慢
```mysql
# 交叉连接: cross join
# 学生表和成绩表关联
select * from student cross join score where student.Sno=score.Sno;
# cross join 返回的是笛卡尔积的数据存在无意义的数据。所以用where过滤掉
# cross join 简写为逗号
select * from student, score where student.Sno=score.Sno;
# 查询每个学生每门课程考多少分
select student.Sname as 姓名, score.cno as 课程编号, score.Degree as 成绩 from student, score where student.Sno=score.Sno;
```
#### 内连接
```mysql
# 内连接: 表1 inner join 表2 on 表1.id=表2.id
# 表1.id于表2.id 描述同一显示事物
select student.Sname as 姓名, score.cno as 课程编号, score.Degree as 成绩
from student inner join score
on student.Sno=score.Sno;
# 如果三张表: 表1 inner join 表2 on 表1.id=表2.id inner join 表3 on 表2.id=表3.id
```
#### 外连接
```mysql
# 左外连接: 表1 left join 表2 on 表1.id-表2.id
-- 返回左表中的所有数据对应右表不存在的数据以nul1的形式返回。
# 右外连接: 表1 right join 表2 on 表1.id-表2.id
-- 返回右表中的所有数据对应左表中不存在的数据以nul1形式返回。
# 哪些学生没有选修课程的
select student.Sname as 姓名
from student left join score on student.sno=score.sno
where student.degree is NULL;
```
![](https://img.081024.xyz/6-MySQL-20240602021704838.jpg)
![](https://img.081024.xyz/6-MySQL-20240602021732743.jpg)
#### 子查询
```mysql
# 子查询:一个查询语句中,嵌套另一个查询语句。
-- 多行子查询: in 和 not in
-- 单行子查询: >, < , >=, <=, !=, 不等于也可以写成<>
# 哪些学生没有选修课程的
select * from student where sno not in (select sno from score);
# 查询成绩表中成绩最高的学生
select * from student
where student.sno=score.sno
and score.degree =
(select max(degree) from score);
```