Files
security-book/01.WEB网站开发/07.MySQL.md
2025-08-27 14:07:52 +08:00

73 KiB
Raw Blame History

MySQL

数据库概念

数据(data)是事实或观察的结果,是对客观事物的逻辑归纳,是用于表示客观事物的未经加工的的原始素材。 数据可以是连续的值,比如声音、图像,称为模拟数据。也可以是离散的,如符号、文字,称为数字数据。 在计算机系统中数据以二进制信息单元0,1的形式表示。 **数据的定义:**数据是指对客观事件进行记录并可以鉴别的符号,是对客观事物的性质、状态以及相互关系等进行记载的物理符号或这些物理符号的组合。它是可识别的、抽象的符号。 DBMSdatabase management system

image.png

DBMS类别

RDBMS

以多张二维表的方式来存储,又给多张表建立了一定的关系(关系型数据库)

NoSQL

nosql 很多以json格式进行存储数据的mogodb

DBMS对比

功能对比
关系型数据库 非关系型数据库
强大的查询功能 ×
强一致性 ×
二级索引 ×
灵活模式 ×
扩展性 ×
性能 ×
特点对比
  • 关系型数据库RDBMS的特点
    • 二维表
    • 典型产品Oracle传统企业MySQL互联网企业
    • 数据存取是通过SQLStructured Query Language结构化查询语言
    • 最大特点数据安全性方面强ACID
  • 非关系型数据库NoSQLNot only SQL的特点
    • 不是否定关系型数据库,而是做关系型数据库的补充

MySQL基础操作

在mysql官方网站可以下载到mysql的各种版本https://downloads.mysql.com/archives/installer/

用户管理

用户的定义

  • username@'主机域'
  • 主机域:可以理解为是Mysql登录的白名单
  • 主机域格式:
    • 10.1.1.12
    • 10.1.0.1%
    • 10.1.0.%
    • 10.1.%.%
    • %
    • localhost
    • 192.168.1.1/255.255.255.
  • 创建用户
mysql> create user user01@'192.168.175.%' identified by '123456';
  • 查看用户
mysql> select user,host from mysql.user;
  • 删除用户
mysql> drop user user01@'192.168.175.%';
  • 修改密码
mysql> set password=PASSOWRD('123456')
mysql> update user set password=PASSWORD('user01') where user='root' and host='localhost';
mysql> grant all privileges on *.* to user01@'192.168.175.%' identified by '123456';
mysql> flush privileges;

用户权限介绍

  • 权限
INSERT,SELECT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN,  PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE
  • 每次设定只能有一个属主,没有属组或其他用户的概念
grant     all privileges    on     *.*    to   user01@''192.168.175.%''  identified by    ''123'';
                权限               作用对象          归属               密码

作用对象分解

  • _*.*_[当前MySQL实例中所有库下的所有表]
  • wordpress.* [当前MySQL实例中wordpress库中所有表单库级别]
  • wordpress.user [当前MySQL实例中wordpress库中的user表单表级别]

企业中权限的设定

  • 开发人员说:给我开一个用户
  • 沟通
    • 你需要对哪些库、表进行操作
    • 你从哪里连接过来
    • 用户名有没有要求
    • 密码要求
    • 发邮件
  • 一般给开发创建用户权限
grant select,update,delete,insert on *.* to 'user01@192.168.175.%' identified by '123456';

实验思考问题

##创建wordpress数据库
create database wordpress;

##使用wordpress库
use wordpress;

##创建t1t2表
create table t1 (id int);
create table t2 (id int);

##创建blog库
create database blog;

##使用blog库
use blog;

##创建t1表
create table tb1 (id int);

授权

1grant select on *.* to wordpress@10.0.0.5% identified by 123;
2grant insert,delete,update on wordpress.* to wordpress@10.0.0.5% identified by 123;
3grant all on wordpress.t1 to wordpress@10.0.0.5% identified by 123;
  • 一个客户端程序使用wordpress用户登陆到10.0.0.51的MySQL后
    • 对t1表的管理能力
    • 对t2表的管理能力
    • 对tb1表的管理能力
    • 同时满足123最终权限是1+2+3
    • 同时满足了1和2两个授权最终权限是1+2
    • 只满足1授权所以只能select
  • 结论
    • 如果在不同级别都包含某个表的管理能力时,权限是相加关系。
    • 但是我们不推荐在多级别定义重复权限。
    • 最常用的权限设定方式是单库级别授权wordpress.*

SQL语句

  • SQL是结构化的查询语句
  • SQL的种类
    • DDL:数据定义语句
    • DCL:数据控制语言
    • DML:数据操作语言
    • DQL:数据查询语言

DDL数据定义语句

  • 对库或者表进行操作的语句
  • 创建数据库
create database db01;
## 创建数据库

create database DB01;
## 数据库名区分大小写(注意windows里面不区分)

show databases;
## 查看数据库(DQL)

show create database db01;
## 查看创建数据库语句

help create database;
## 查看创建数据库语句帮助

create database db02 charset utf8;
## 创建数据库的时候添加属性
  • 删除数据库
drop database db02;
## 删除数据库db02
  • 修改定义库
alter database db01 charset utf8;
show create database db01;
  • 创建表
help create table;

## 查看创表语句的帮助
create table student(
sid int,
sname varchar(20),
sage tinyint,
sgender enum('m','f'),
comtime datetime
);
## 创建表,并且定义每一列
  • 数据类型(下面有完整的)
    int 整数 -231~230
    tinyint 整数 -128~127
    varchar 字符类型(可变长)
    char 字符类型(定长)
    enum 枚举类型
    datetime 时间类型 年月日时分秒
create table student(
sid int not null primary key auto_increment comment '学号',
sname varchar(20) not null comment '学生姓名',
sgender enum('m','f') not null default 'm' comment '学生性别',
cometime datetime not null comment '入学时间'
)charset utf8 engine innodb;
## 带数据属性创建学生表

show create table student;
## 查看建表语句

show tables;
## 查看表

desc student;
## 查看表中列的定义信息
  • 数据属性

    not null 不允许是空
    primary key 主键(唯一且非空)
    auto_increment 自增此列必须是primary key或者unique key
    unique key 单独的唯一的
    default 默认值
    unsigned 非负数
    comment 注释
  • 删除表

drop table student;
  • 修改表的定义
alter table student rename stu;
## 修改表名

alter table stu add age int;
## 添加列和列数据类型的定义

alter table stu add test varchar(20),add qq int;
## 添加多个列

alter table stu add classid varchar(20) first;
## 指定位置进行添加列(表首)

alter table stu add phone int after age;
## 指定位置进行添加列(指定列)

alter table stu drop qq;
## 删除指定的列及定义

alter table stu modify sid varchar(20);
## 修改列及定义(列属性)

alter table stu change phone telphone char(20);
## 修改列及定义(列名及属性)

多表结构的创建与分析

如何找出两张表之间的关系 分析步骤: 1. 先站在左表的角度去找 是否左表的多条记录可以对应右表的一条记录如果是则证明左表的一个字段foreign key 右表一个字段通常是id **2. **再站在右表的角度去找 是否右表的多条记录可以对应左表的一条记录如果是则证明右表的一个字段foreign key 左表一个字段通常是id **3. **总结: 多对一 如果只有步骤1成立则是左表多对一右表 如果只有步骤2成立则是右表多对一左表 **多对多 ** 如果步骤1和2同时成立则证明这两张表时一个双向的多对一即多对多,需要定义一个这两张表的关系表来专门存放二者的关系

一对一 如果1和2都不成立而是左表的一条记录唯一对应右表的一条记录反之亦然。这种情况很简单就是在左表foreign key右表的基础上将左表的外键字段设置成unique即可

建立表之间的关系

一对多或称为多对一 创建三张表:出版社,作者信息,书籍列表 一对多(或多对一):一个出版社可以出版多本书

create table press(
id int primary key auto_increment,
name varchar(20)
);

create table book(
id int primary key auto_increment,
name varchar(20),
press_id int not null,
foreign key(press_id) references press(id)
on delete cascade
on update cascade
);


insert into press(name) values
('英格科技出版社'),
('许老师YYDS出版社'),
('安全渗透出版社')
;

insert into book(name,press_id) values
('九阳神功',1),
('九阴真经',2),
('九阴白骨爪',2),
('独孤九剑',3),
('降龙十巴掌',2),
('葵花宝典',3)
;

多对多 三张表:出版社,作者信息,书 多对多:一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多

create table author(
id int primary key auto_increment,
name varchar(20)
);

##这张表就存放作者表与书表的关系,即查询二者的关系查这表就可以了
create table author2book(
id int not null unique auto_increment,
author_id int not null,
book_id int not null,
constraint fk_author foreign key(author_id) references author(id)
on delete cascade
on update cascade,
constraint fk_book foreign key(book_id) references book(id)
on delete cascade
on update cascade,
primary key(author_id,book_id)
);

##插入四个作者,id依次排开
insert into author(name) values('zhangsan'),('lisi'),('wangwu'),('xuliu');

##每个作者与自己的代表作如下
zhangsan: 
九阳神功
九阴真经
九阴白骨爪
独孤九剑
降龙十巴掌
葵花宝典
lisi: 
九阳神功
葵花宝典
wangwu:
独孤九剑
降龙十巴掌
葵花宝典
xuliu:
九阳神功

insert into author2book(author_id,book_id) values
(1,1),
(1,2),
(1,3),
(1,4),
(1,5),
(1,6),
(2,1),
(2,6),
(3,4),
(3,5),
(3,6),
(4,1)
;

一对一 两张表:博客表和客户表 一对一:一个用户只有一个博客

create table customer(
id int primary key auto_increment,
name varchar(20)
)engine=innodb default charset=utf8;

create table blog(
id int primary key auto_increment,
url varchar(50),
name_id int unique,
constraint fk_id foreign key(name_id) references customer(id)
on delete cascade
on update cascade
)engine=innodb default charset=utf8;

insert into customer(name) values
('chensong'),('songge'),('songsong');

insert into blog(url,name_id) values
('xxxx',1),('yyyy',2),('zzzz',3);

练习

根据表结构合理设计表与表之间的主外键关系和约束,并完成表结构的创建。

参考答案

create table class(
cid int primary key auto_increment,
caption varchar(20)
)engine=innodb default charset=utf8;

create table student(
sid int primary key auto_increment,
sname varchar(20),
gender enum('男','女'),
class_id int,
foreign key(class_id) references class(cid)
)engine=innodb default charset=utf8;

create table teacher(
tid int primary key auto_increment,
tname varchar(20)
)engine=innodb default charset=utf8;

create table course(
cid int primary key auto_increment,
cname varchar(20),
teach_id int,
foreign key(teach_id) references teacher(tid)
)engine=innodb default charset=utf8;

create table score(
sid int primary key auto_increment,
student_id int,
foreign key(student_id) references student(sid),
corse_id int,
foreign key(corse_id) references course(cid),
number int
)engine=innodb default charset=utf8;

insert into class(caption) value
('三年一班'),
('一年二班'),
('三年二班');

insert into student(sname, gender, class_id) value
('东尼大木','男',1),
('加藤鹰','男',1),
('山形健','女',2);

insert into teacher(tname) value
('波多'),
('苍空'),
('饭岛');

insert into course(cname, teach_id) value
('生物',1),
('体育',1),
('思想品德',2);

insert into score(student_id, corse_id, number) value
(1,1,60),
(1,2,59),
(2,2,100);

select * from class;
select * from student;
select * from teacher;
select * from course;
select * from score;

MySQL支持的数据类型

数值类型

MySQL支持所有标准SQL数值数据类型 这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。 关键字INT是INTEGER的同义词关键字DEC是DECIMAL的同义词。 MySQL支持的整数类型有TINYINT、MEDIUMINT和BIGINT。下面的表显示了需要的每个整数类型的存储和范围。 对于小数的表示MYSQL分为两种方式浮点数和定点数。浮点数包括float(单精度)和double(双精度),而定点数只有decimal一种在mysql中以字符串的形式存放比浮点数更精确适合用来表示货币等精度高的数据。 BIT数据类型保存位字段值并且支持MyISAM、MEMORY、InnoDB和BDB表。

类型 大小 范围(有符号) 范围无符号unsigned约束 用途
TINYINT 1 字节 (-128127) (0255) 小整数值
SMALLINT 2 字节 (-32 76832 767) (065 535) 大整数值
MEDIUMINT 3 字节 (-8 388 6088 388 607) (016 777 215) 大整数值
INT或INTEGER 4 字节 (-2 147 483 6482 147 483 647) (04 294 967 295) 大整数值
BIGINT 8 字节 (-9 233 372 036 854 775 8089 223 372 036 854 775 807) (018 446 744 073 709 551 615) 极大整数值
FLOAT 4 字节
float(255,30) (-3.402 823 466 E+38-1.175 494 351 E-38)0(1.175 494 351 E-383.402 823 466 351 E+38) 0(1.175 494 351 E-383.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 字节
double(255,30) (-1.797 693 134 862 315 7 E+308-2.225 073 858 507 201 4 E-308)0(2.225 073 858 507 201 4 E-3081.797 693 134 862 315 7 E+308) 0(2.225 073 858 507 201 4 E-3081.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) 如果M>D为M+2否则为D+2
double(65,30) 依赖于M和D的值 依赖于M和D的值 小数值
## 创建表一个是默认宽度的int,一个是指定宽度的int(5)
mysql> create table t1 (id1 int,id2 int(5));
Query OK, 0 rows affected (0.02 sec)

## t1中插入数据11
mysql> insert into t1 values (1,1);
Query OK, 1 row affected (0.01 sec)

## 可以看出结果上并没有异常
mysql> select * from t1;
+------+------+
| id1  | id2  |
+------+------+
|    1 |    1 |
+------+------+
1 row in set (0.00 sec)

## 那么当我们插入了比宽度更大的值,会不会发生报错呢?
mysql> insert into t1 values (111111,111111);
Query OK, 1 row affected (0.00 sec)

## 答案是否定的,id2仍然显示了正确的数值,没有受到宽度限制的影响
mysql> select * from t1;
+------------+--------+
| id1        | id2    |
+------------+--------+
| 0000000001 |  00001 |
| 0000111111 | 111111 |
+------------+--------+
2 rows in set (0.00 sec)

## 修改id1字段 给字段添加一个unsigned表示无符号
mysql> alter table t1 modify id1 int unsigned;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc t1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id1   | int(10) unsigned | YES  |     | NULL    |       |
| id2   | int(5)           | YES  |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

## 当给id1添加的数据大于214748364时,可以顺利插入
mysql> insert into t1 values (2147483648,2147483647);
Query OK, 1 row affected (0.00 sec)

## 当给id2添加的数据大于214748364时,会报错
mysql> insert into t1 values (2147483647,2147483648);
ERROR 1264 (22003): Out of range value for column 'id2' at row 1
## 创建表的三个字段分别为floatdouble和decimal参数表示一共显示5位,小数部分占2
mysql> create table t2 (id1 float(5,2),id2 double(5,2),id3 decimal(5,2));
Query OK, 0 rows affected (0.02 sec)

## 向表中插入1.23,结果正常
mysql> insert into t2 values (1.23,1.23,1.23);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
+------+------+------+
1 row in set (0.00 sec)

## 向表中插入1.234,会发现4都被截断了
mysql> insert into t2 values (1.234,1.234,1.234);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
| 1.23 | 1.23 | 1.23 |
+------+------+------+
2 rows in set (0.00 sec)

## 向表中插入1.235发现数据虽然被截断,但是遵循了四舍五入的规则
mysql> insert into t2 values (1.235,1.235,1.235);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
| 1.23 | 1.23 | 1.23 |
| 1.24 | 1.24 | 1.24 |
+------+------+------+
3 rows in set (0.00 sec)

## 建新表去掉参数约束
mysql> create table t3 (id1 float,id2 double,id3 decimal);
Query OK, 0 rows affected (0.02 sec)

## 分别插入1.234
mysql> insert into t3 values (1.234,1.234,1.234);
Query OK, 1 row affected, 1 warning (0.00 sec)

## 发现decimal默认值是(10,0)的整数
mysql> select * from t3;
+-------+-------+------+
| id1   | id2   | id3  |
+-------+-------+------+
| 1.234 | 1.234 |    1 |
+-------+-------+------+
1 row in set (0.00 sec)

## 当对小数位没有约束的时候,输入超长的小数,会发现float和double的区别
mysql> insert into t3 values (1.2355555555555555555,1.2355555555555555555,1.2355555555555555555555);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t3;
+---------+--------------------+------+
| id1     | id2                | id3  |
+---------+--------------------+------+
|   1.234 |              1.234 |    1 |
| 1.23556 | 1.2355555555555555 |    1 |
+---------+--------------------+------+
2 rows in set (0.00 sec)

日期和时间类型

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。 每个时间类型有一个有效值范围和一个"零"值当指定不合法的MySQL不能表示的值时使用"零"值。 TIMESTAMP类型有专有的自动更新特性将在后面描述。

类型 大小 (字节) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 年月日
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时分秒
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 年月日时分秒
TIMESTAMP 4 1970-01-01 00:00:00/2038
结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳
MariaDB [db2]> create table time(d date,t time,dt datetime);
Query OK, 0 rows affected (0.00 sec)

MariaDB [db2]> desc time;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d     | date     | YES  |     | NULL    |       |
| t     | time     | YES  |     | NULL    |       |
| dt    | datetime | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)

MariaDB [db2]> insert into time values(now(),now(),now());
Query OK, 1 row affected, 2 warnings (0.00 sec)

MariaDB [db2]> select * from time;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2019-02-27 | 11:29:32 | 2019-02-27 11:29:32 |
+------------+----------+---------------------+
1 row in set (0.00 sec)

MariaDB [db2]> insert into time values (null,null,null);
Query OK, 1 row affected (0.00 sec)

MariaDB [db2]> select * from time;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2019-02-27 | 11:29:32 | 2019-02-27 11:29:32 |
| NULL       | NULL     | NULL                |
+------------+----------+---------------------+
2 rows in set (0.00 sec)
mysql> create table t5 (id1 timestamp);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t5;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id1   | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
1 row in set (0.00 sec)

## 插入数据null,会自动插入当前时间的时间
mysql> insert into t5 values (null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t5;
+---------------------+
| id1                 |
+---------------------+
| 2019-02-21 14:56:50 |
+---------------------+
1 row in set (0.00 sec)

##添加一列 默认值是'0000-00-00 00:00:00'
mysql> alter table t5 add id2 timestamp;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table t5 \G;
*************************** 1. row ***************************
       Table: t5
Create Table: CREATE TABLE `t5` (
  `id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

ERROR: 
No query specified

## 手动修改新的列默认值为当前时间
mysql> alter table t5 modify id2 timestamp default current_timestamp;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table t5 \G;
*************************** 1. row ***************************
       Table: t5
Create Table: CREATE TABLE `t5` (
  `id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id2` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

ERROR: 
No query specified

mysql> insert into t5 values (null,null);
Query OK, 1 row affected (0.01 sec)

mysql> select * from t5;
+---------------------+---------------------+
| id1                 | id2                 |
+---------------------+---------------------+
| 2019-02-21 14:56:50 | 0000-00-00 00:00:00 |
| 2019-02-21 14:59:31 | 2019-02-21 14:59:31 |
+---------------------+---------------------+
2 rows in set (0.00 sec)
mysql> create table t6 (t1 timestamp);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t6;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| t1    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
1 row in set (0.01 sec)

mysql> insert into t6 values (19700101080001);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t6;
+---------------------+
| t1                  |
+---------------------+
| 1970-01-01 08:00:01 |
+---------------------+
1 row in set (0.00 sec)
## timestamp时间的下限是19700101080001
mysql> insert into t6 values (19700101080000);
ERROR 1292 (22007): Incorrect datetime value: '19700101080000' for column 't1' at row 1

mysql> insert into t6 values ('2038-01-19 11:14:07');
Query OK, 1 row affected (0.00 sec)
## timestamp时间的上限是2038-01-19 11:14:07
mysql> insert into t6 values ('2038-01-19 11:14:08');
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 11:14:08' for column 't1' at row 1
mysql> 
mysql> create table t7 (y year);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t7 values (2019);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t7;
+------+
| y    |
+------+
| 2019 |
+------+
1 row in set (0.00 sec)
mysql> create table t8 (dt datetime);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t8 values ('2019-2-26 12:20:10');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t8 values ('2019/2/26 12+20+10');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t8 values ('20190226122010');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t8 values (20190926122010);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t8;
+---------------------+
| dt                  |
+---------------------+
| 2019-02-26 12:20:10 |
| 2019-02-26 12:20:10 |
| 2019-02-26 12:20:10 |
| 2019-02-26 12:20:10 |
+---------------------+
4 rows in set (0.00 sec)

字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。

类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65 535字节 二进制形式的长文本数据
TEXT 0-65 535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据

CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。 CHAR列的长度固定为创建表是声明的长度,范围(0-255);而VARCHAR的值是可变长字符串范围(0-65535)。

mysql> create table t9 (v varchar(4),c char(4));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t9 values ('ab  ','ab  ');
Query OK, 1 row affected (0.00 sec)

## 在检索的时候char数据类型会去掉空格
mysql> select * from t9;
+------+------+
| v    | c    |
+------+------+
| ab   | ab   |
+------+------+
1 row in set (0.00 sec)

## 来看看对查询结果计算的长度
mysql> select length(v),length(c) from t9;
+-----------+-----------+
| length(v) | length(c) |
+-----------+-----------+
|         4 |         2 |
+-----------+-----------+
1 row in set (0.00 sec)

## 给结果拼上一个加号会更清楚
mysql> select concat(v,'+'),concat(c,'+') from t9;
+---------------+---------------+
| concat(v,'+') | concat(c,'+') |
+---------------+---------------+
| ab  +         | ab+           |
+---------------+---------------+
1 row in set (0.00 sec)

## 当存储的长度超出定义的长度,会截断
mysql> insert into t9 values ('abcd  ','abcd  ');
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> select * from t9;
+------+------+
| v    | c    |
+------+------+
| ab   | ab   |
| abcd | abcd |
+------+------+
2 rows in set (0.00 sec)

BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR不同的是它们包含二进制字符串而不要非二进制字符串。也就是说它们包含字节字符串而不是字符字符串。这说明它们没有字符集并且排序和比较基于列值字节的数值值。 BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。 有 4 种 TEXT 类型TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。

ENUM和SET类型

ENUM中文名称叫枚举类型它的值范围需要在创建表时通过枚举方式显示。ENUM只允许从值集合中选取单个值,而不能一次取多个值。 SET和ENUM非常相似也是一个字符串对象里面可以包含0-64个成员。根据成员的不同存储上也有所不同。set类型可以允许值集合中任意选择1或多个元素进行组合。对超出范围的内容将不允许注入,而对重复的值将进行自动去重。

类型 大小 用途
ENUM 对1-255个成员的枚举需要1个字节存储;
对于255-65535个成员需要2个字节存储;
最多允许65535个成员。 单选:选择性别
SET 1-8个成员的集合占1个字节
9-16个成员的集合占2个字节
17-24个成员的集合占3个字节
25-32个成员的集合占4个字节
33-64个成员的集合占8个字节 多选:兴趣爱好
mysql> create table t10 (name char(20),gender enum('female','male'));
Query OK, 0 rows affected (0.01 sec)

## 选择enum('female','male')中的一项作为gender的值,可以正常插入
mysql> insert into t10 values ('zhangsan','male');
Query OK, 1 row affected (0.00 sec)

## 不能同时插入'male,female'两个值,也不能插入不属于'male,female'的值
mysql> insert into t10 values ('zhangsan','male,female');
ERROR 1265 (01000): Data truncated for column 'gender' at row 1

mysql> create table t11 (name char(20),hobby set('抽烟','喝酒','烫头','翻车'));
Query OK, 0 rows affected (0.01 sec)

## 可以任意选择set('抽烟','喝酒','烫头','翻车')中的项,并自带去重功能
mysql> insert into t11 values ('zhangsan','烫头,喝酒,烫头');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t11;
+----------+---------------+
|    name  |  hobby        |
+----------+---------------+
| zhangsan |  喝酒,烫头     |
+----------+---------------+
1 row in set (0.00 sec)

## 不能选择不属于set('抽烟','喝酒','烫头','翻车')中的项,
mysql> insert into t11 values ('zhangsan','烫头,翻车,看妹子');
ERROR 1265 (01000): Data truncated for column 'hobby' at row 1

表的完整性约束

概述

为了防止不符合规范的数据进入数据库在用户对数据进行插入、修改、删除等操作时DBMS自动按照一定的约束条件对数据进行监测使不符合规范的数据不能进入数据库以确保数据库中存储的数据正确、有效、相容。  约束条件与数据类型的宽度一样,都是可选参数,主要分为以下几种:

  1. NOT NULL :非空约束,指定某列不能为空;
  2. UNIQUE : 唯一约束,指定某列或者几列组合不能重复
  3. PRIMARY KEY :主键,指定该列的值可以唯一地标识该列记录
  4. FOREIGN KEY :外键,指定该行记录从属于主表中的一条记录,主要用于参照完整性

NOT NULL

是否可空null表示空非字符串 not null - 不可空 null - 可空(默认)

mysql> create table t12 (id int not null);
Query OK, 0 rows affected (0.02 sec)

mysql> select * from t12;
Empty set (0.00 sec)

mysql> desc t12;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)

##不能向id列插入空元素 
mysql> insert into t12 values (null);
ERROR 1048 (23000): Column 'id' cannot be null

mysql> insert into t12 values (1);
Query OK, 1 row affected (0.01 sec)

DEFAULT

约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。 默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值

mysql> create table t13 (id1 int not null,id2 int not null default 222);
Query OK, 0 rows affected (0.01 sec)

mysql> desc t13;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id1   | int(11) | NO   |     | NULL    |       |
| id2   | int(11) | NO   |     | 222     |       |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.01 sec)

## 只向id1字段添加值,会发现id2字段会使用默认值填充
mysql> insert into t13 (id1) values (111);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t13;
+-----+-----+
| id1 | id2 |
+-----+-----+
| 111 | 222 |
+-----+-----+
1 row in set (0.00 sec)

## id1字段不能为空,所以不能单独向id2字段填充值
mysql> insert into t13 (id2) values (223);
ERROR 1364 (HY000): Field 'id1' doesn't have a default value

## 向id1id2中分别填充数据id2的填充数据会覆盖默认值
mysql> insert into t13 (id1,id2) values (112,223);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t13;
+-----+-----+
| id1 | id2 |
+-----+-----+
| 111 | 222 |
| 112 | 223 |
+-----+-----+
2 rows in set (0.00 sec)

设置严格模式:

  • 不支持对not null字段插入null值
  • 不支持对自增长字段插入null值
  • 不支持text字段有默认值
直接在mysql中生效(重启失效):
mysql>set sql_mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";

配置文件添加(永久失效)
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

UNIQUE

唯一约束,指定某列或者几列组合不能重复

方法一:
create table department1(
id int,
name varchar(20) unique,
comment varchar(100)
);


方法二:
create table department2(
id int,
name varchar(20),
comment varchar(100),
unique(name)
);


mysql> insert into department1 values(1,'IT','技术');
Query OK, 1 row affected (0.00 sec)
mysql> insert into department1 values(1,'IT','技术');
ERROR 1062 (23000): Duplicate entry 'IT' for key 'name'
mysql> create table t1(id int not null unique);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   | PRI | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
create table service(
id int primary key auto_increment,
name varchar(20),
host varchar(15) not null,
port int not null,
unique(host,port) #联合唯一
);

mysql> insert into service values
    -> (1,'nginx','192.168.0.10',80),
    -> (2,'haproxy','192.168.0.20',80),
    -> (3,'mysql','192.168.0.30',3306)
    -> ;
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> insert into service(name,host,port) values('nginx','192.168.0.10',80);
ERROR 1062 (23000): Duplicate entry '192.168.0.10-80' for key 'host'

PRIMARY KEY

主键为了保证表中的每一条数据的该字段都是表格中的唯一值。换言之,它是用来独一无二地确认一个表格中的每一行数据。 主键可以包含一个字段或多个字段。当主键包含多个栏位时,称为组合键 (Composite Key),也可以叫联合主键。 主键可以在建置新表格时设定 (运用 CREATE TABLE 语句),或是以改变现有的表格架构方式设定 (运用 ALTER TABLE)。 主键必须唯一,主键值非空;可以是单一字段,也可以是多字段组合。

  1. 单字段主键
============单列做主键===============
##方法一:not null+unique
create table department1(
id int not null unique, #主键
name varchar(20) not null unique,
comment varchar(100)
);

mysql> desc department1;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | NO   | UNI | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

##方法二:在某一个字段后用primary key
create table department2(
id int primary key, #主键
name varchar(20),
comment varchar(100)
);

mysql> desc department2;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.00 sec)

##方法三:在所有字段后单独定义primary key
create table department3(
id int,
name varchar(20),
comment varchar(100),
primary key(id); #创建主键并为其命名pk_name

mysql> desc department3;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
rows in set (0.01 sec)

## 方法四:给已经建成的表添加主键约束
mysql> create table department4(
    -> id int,
    -> name varchar(20),
    -> comment varchar(100));
Query OK, 0 rows affected (0.01 sec)

mysql> desc department4;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | YES  |     | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> alter table department4 modify id int primary key;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc department4;
+---------+--------------+------+-----+---------+-------+
| Field   | Type         | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+-------+
| id      | int(11)      | NO   | PRI | NULL    |       |
| name    | varchar(20)  | YES  |     | NULL    |       |
| comment | varchar(100) | YES  |     | NULL    |       |
+---------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
  1. 多字段主键
==================多列做主键================
create table service(
ip varchar(15),
port char(5),
service_name varchar(10) not null,
primary key(ip,port)
);


mysql> desc service;
+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| ip           | varchar(15) | NO   | PRI | NULL    |       |
| port         | char(5)     | NO   | PRI | NULL    |       |
| service_name | varchar(10) | NO   |     | NULL    |       |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into service values
    -> ('172.16.45.10','3306','mysqld'),
    -> ('172.16.45.11','3306','mariadb')
    -> ;
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into service values ('172.16.45.10','3306','nginx');
ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY'

AUTO_INCREMENT

约束字段为自动增长被约束的字段必须同时被key约束

##不指定id,则自动增长
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> desc student;
+-------+-----------------------+------+-----+---------+----------------+
| Field | Type                  | Null | Key | Default | Extra          |
+-------+-----------------------+------+-----+---------+----------------+
| id    | int(11)               | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20)           | YES  |     | NULL    |                |
| sex   | enum('male','female') | YES  |     | male    |                |
+-------+-----------------------+------+-----+---------+----------------+
mysql> insert into student(name) values
    -> ('egon'),
    -> ('alex')
    -> ;

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
|  2 | alex | male |
+----+------+------+


##也可以指定id
mysql> insert into student values(4,'asb','female');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student values(7,'wsb','female');
Query OK, 1 row affected (0.00 sec)

mysql> select * from student;
+----+------+--------+
| id | name | sex    |
+----+------+--------+
|  1 | egon | male   |
|  2 | alex | male   |
|  4 | asb  | female |
|  7 | wsb  | female |
+----+------+--------+


##对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长
mysql> delete from student;
Query OK, 4 rows affected (0.00 sec)

mysql> select * from student;
Empty set (0.00 sec)

mysql> insert into student(name) values('ysb');
mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  8 | ysb  | male |
+----+------+------+

##应该用truncate清空表,比起delete一条一条地删除记录truncate是直接清空表,在删除大表时用它
mysql> truncate student;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into student(name) values('egon');
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  1 | egon | male |
+----+------+------+
row in set (0.00 sec)

知识扩展

##在创建完表后,修改自增字段的起始值
mysql> create table student(
    -> id int primary key auto_increment,
    -> name varchar(20),
    -> sex enum('male','female') default 'male'
    -> );

mysql> alter table student auto_increment=3;

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

mysql> insert into student(name) values('egon');
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------+------+
| id | name | sex  |
+----+------+------+
|  3 | egon | male |
+----+------+------+
row in set (0.00 sec)

mysql> show create table student;
.......
ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8


##也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外
create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
)auto_increment=3;




##设置步长
sqlserver:自增步长
    基于表级别
    create table t1
        id int。。。
    engine=innodb,auto_increment=2 步长=2 default charset=utf8

mysql自增的步长
    show session variables like 'auto_inc%';
    
    #基于会话级别
    set session auto_increment_increment=2 #修改会话级别的步长

    #基于全局级别的
    set global auto_increment_increment=2 #修改全局级别的步长(所有会话都生效)


##!!!注意了注意了注意了!!!
If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 
翻译:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略 ,这相当于第一步步子就迈大了,扯着了蛋
比如:设置auto_increment_offset=3auto_increment_increment=2




mysql> set global auto_increment_increment=5;
Query OK, 0 rows affected (0.00 sec)

mysql> set global auto_increment_offset=3;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'auto_incre%'; #需要退出重新登录
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1     |
| auto_increment_offset    | 1     |
+--------------------------+-------+



create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> insert into student(name) values('egon1'),('egon2'),('egon3');
mysql> select * from student;
+----+-------+------+
| id | name  | sex  |
+----+-------+------+
|  3 | egon1 | male |
|  8 | egon2 | male |
| 13 | egon3 | male |
+----+-------+------+

步长:auto_increment_increment,起始偏移量:auto_increment_offset

FOREIKEY

假设我们要描述所有公司的员工,需要描述的属性有这些 工号 姓名 部门 公司有3个部门但是有1个亿的员工那意味着部门这个字段需要重复存储部门名字越长越浪费 解决方法: 我们完全可以定义一个部门表 然后让员工信息表关联该表如何关联即foreign key

mysql> create table departments (dep_id int(4),dep_name varchar(11));
Query OK, 0 rows affected (0.02 sec)

mysql> desc departments;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| dep_id   | int(4)      | YES  |     | NULL    |       |
| dep_name | varchar(11) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

## 创建外键不成功
mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id));
ERROR 1215 (HY000): Cannot add foreign key 

## 设置dep_id非空,仍然不能成功创建外键
mysql> alter table departments modify dep_id int(4) not null;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc departments;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| dep_id   | int(4)      | NO   |     | NULL    |       |
| dep_name | varchar(11) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id));
ERROR 1215 (HY000): Cannot add foreign key constraint

## 当设置字段为unique唯一字段时,设置该字段为外键成功
mysql> alter table departments modify dep_id int(4) unique;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc departments;                                                                                                       +----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| dep_id   | int(4)      | YES  | UNI | NULL    |       |
| dep_name | varchar(11) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> create table staff_info (s_id int,name varchar(20),dep_id int,foreign key(dep_id) references departments(dep_id));
Query OK, 0 rows affected (0.02 sec)
##表类型必须是innodb存储引擎,且被关联的字段,即references指定的另外一个表的字段,必须保证唯一
create table department(
id int primary key,
name varchar(20) not null
)engine=innodb;

##dpt_id外键,关联父表(department主键id),同步更新,同步删除
create table employee(
id int primary key,
name varchar(20) not null,
dpt_id int,
foreign key(dpt_id)
references department(id)
on delete cascade  # 连级删除
on update cascade # 连级更新
)engine=innodb;


##先往父表department中插入记录
insert into department values
(1,'教质部'),
(2,'技术部'),
(3,'人力资源部');


##再往子表employee中插入记录
insert into employee values
(1,'yuan',1),
(2,'nezha',2),
(3,'egon',2),
(4,'alex',2),
(5,'wusir',3),
(6,'张三三',3),
(7,'皮卡丘',3),
(8,'程咬金',3),
(9,'程咬银',3)
;


##删父表department,子表employee中对应的记录跟着删
mysql> delete from department where id=2;
Query OK, 1 row affected (0.00 sec)

mysql> select * from employee;
+----+-----------+--------+
| id | name      | dpt_id |
+----+-----------+--------+
|  1 | yuan      |      1 |
|  5 | wusir     |      3 |
|  6 | 张三三    |      3 |
|  7 | 皮卡丘    |      3 |
|  8 | 程咬金    |      3 |
|  9 | 程咬银    |      3 |
+----+-----------+--------+
6 rows in set (0.00 sec)


##更新父表department,子表employee中对应的记录跟着改
mysql> update department set id=2 where id=3;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from employee;
+----+-----------+--------+
| id | name      | dpt_id |
+----+-----------+--------+
|  1 | yuan      |      1 |
|  5 | wusir     |      2 |
|  6 | 张三三    |      2 |
|  7 | 皮卡丘    |      2 |
|  8 | 程咬金    |      2 |
|  9 | 程咬银    |      2 |
+----+-----------+--------+
6 rows in set (0.00 sec)

DCL数据操控语言

  • DCL是针对权限进行控制
  • 授权
grant all on *.* to root@'192.168.175.%' identified by '123456'
## 授予root@'192.168.175.%'用户所有权限(非超级管理员)
grant all on *.* to root@'192.168.175.%' identified by '123456' with grant option;
## 授权一个超级管路员
max_queries_per_hour:一个用户每小时可发出的查询数量
max_updates_per_hour:一个用户每小时可发出的更新数量
max_connections_per_hour:一个用户每小时可连接到服务器的次数
max_user_connections:允许同时连接数量
  • 收回权限
revoke select on *.* from root@'192.168.175.%';
## 收回select权限
show grants for root@'192.168.175.%';
## 查看权限

DML数据操作语言

  • 操作表中的数据
  • 插入数据
insert into stu valus('linux01',1,NOW(),'zhangsan',20,'m',NOW(),110,123456);
## 基础用法,插入数据
insert into stu(classid,birth.sname,sage,sgender,comtime,telnum,qq) values('linux01',1,NOW(),'zhangsan',20,'m',NOW(),110,123456);
## 规范用法,插入数据
insert into stu(classid,birth.sname,sage,sgender,comtime,telnum,qq) values('linux01',1,NOW(),'zhangsan',20,'m',NOW(),110,123456),
('linux02',2,NOW(),'zhangsi',21,'f',NOW(),111,1234567);
## 插入多条数据
  • 更新数据
update student set sgender='f';
## 不规范
update student set sgender='f' where sid=1;
## 规范update修改
update student set sgender='f' where 1=1;
## 如果非要全表修改
update mysql.user set password=PASSWORD('123456') where user='root' and host='localhost';
## 修改密码,需要刷新权限flush privileges
  • 删除数据
delete from student;
## 不规范
delete from student where sid=3;
## 规范删除(危险)
truncate table student;
## DDL清空表中的内容
  • 使用伪删除
    • 有时候一些重要数据不能直接删除,只能伪删除,因为以后还得使用呢
    • 使用update代替delete将状态改成删除状态在查询的时候就可以不显示被标记删除的数据
alter table student add status enum(1,0) default 1;
## 额外添加一个状态列
update student set status='0' where sid=1;
## 使用update
select * from student where status=1;
## 应用查询存在的数据

DQL数据查询语言

单表查询

单表查询语法

SELECT 字段1,字段2... FROM 表名
                     WHERE 条件
                     GROUP BY field
                     HAVING 筛选
                     ORDER BY field
                     LIMIT 限制条数

关键字执行优先级

from
where
group by
having
select
distinct
order by
limit
  1. 找到表:from
  2. 拿着where指定的约束条件去文件/表中取出一条条记录
  3. 将取出的一条条记录进行分组group by如果没有group by则整体作为一组
  4. 将分组的结果进行having过滤
  5. 执行select
  6. 去重
  7. 将结果按条件排序order by
  8. 限制结果的显示条数

简单查询

create table employee(
id int not null unique auto_increment,
emp_name varchar(20) not null,
sex enum('male','female') not null default 'male',
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, 
depart_id int
)engine=innodb default charset=utf8;

insert into employee(emp_name,sex,age,hire_date,post,salary,office,depart_id) values
('草莓','male',18,'20170301','teacher',7300.33,401,1), #以下是教学部
('蓝莓','male',78,'20150302','teacher',1000000.31,401,1),
('黑莓','male',81,'20130305','teacher',8300,401,1),
('桑葚','male',73,'20140701','teacher',3500,401,1),
('覆盆子','male',28,'20121101','teacher',2100,401,1),
('葡萄','female',18,'20110211','teacher',9000,401,1),
('青提','male',18,'19000301','teacher',30000,401,1),
('红提','male',48,'20101111','teacher',10000,401,1),

('蘑菇','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
('洋葱','female',38,'20101101','sale',2000.35,402,2),
('大葱','female',18,'20110312','sale',1000.37,402,2),
('大蒜','female',18,'20160513','sale',3000.29,402,2),
('甜椒','female',28,'20170127','sale',4000.33,402,2),

('慕斯','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
('西米露','male',18,'19970312','operation',20000,403,3),
('鲜奶吐司','female',18,'20130311','operation',19000,403,3),
('绿茶布丁','male',18,'20150411','operation',18000,403,3),
('葡式蛋塔','female',18,'20140512','operation',17000,403,3);
##简单查询
    SELECT id,emp_name,sex,age,hire_date,post,post_comment,salary,office,depart_id 
    FROM employee;

    SELECT * FROM employee;

    SELECT emp_name,salary FROM employee;

##避免重复DISTINCT
    SELECT DISTINCT post FROM employee;    

##通过四则运算查询
    SELECT emp_name, salary*12 FROM employee;
    SELECT emp_name, salary*12 AS Annual_salary FROM employee;
    SELECT emp_name, salary*12 Annual_salary FROM employee;

##定义显示格式
   CONCAT() 函数用于连接字符串
   SELECT CONCAT('姓名: ',emp_name,'  年薪: ', salary*12)  AS Annual_salary 
   FROM employee;
   
   CONCAT_WS() 第一个参数为分隔符
   SELECT CONCAT_WS(':',emp_name,salary*12)  AS Annual_salary 
   FROM employee;

   结合CASE语句
   SELECT
       (
           CASE
           WHEN emp_name = '草莓' THEN
               emp_name
           WHEN emp_name = '蘑菇' THEN
               CONCAT(emp_name,'_BIGSB')
           ELSE
               concat(emp_name, 'SB')
           END
       ) as new_name
   FROM
       employee;

where约束

where字句中可以使用

  1. 比较运算符:> < >= <= <> !=
  2. between 80 and 100 值在80到100之间
  3. in(80,90,100) 值是80或90或100
  4. like '123%'
    1. pattern可以是%或_
    2. %表示任意多字符
    3. _表示一个字符 
  5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
##1:单条件查询
    SELECT emp_name FROM employee
        WHERE post='sale';
        
##2:多条件查询
    SELECT emp_name,salary FROM employee
        WHERE post='teacher' AND salary>10000;

##3:关键字BETWEEN AND
    SELECT emp_name,salary FROM employee 
        WHERE salary BETWEEN 10000 AND 20000;

    SELECT emp_name,salary FROM employee 
        WHERE salary NOT BETWEEN 10000 AND 20000;
    
##4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)
    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment IS NULL;

    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment IS NOT NULL;
        
    SELECT emp_name,post_comment FROM employee 
        WHERE post_comment=''; 注意''是空字符串,不是null
    ps
        执行
        update employee set post_comment='' where id=2;
        再用上条查看,就会有结果了

##5:关键字IN集合查询
    SELECT emp_name,salary FROM employee 
        WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
    
    SELECT emp_name,salary FROM employee 
        WHERE salary IN (3000,3500,4000,9000) ;

    SELECT emp_name,salary FROM employee 
        WHERE salary NOT IN (3000,3500,4000,9000) ;

##6:关键字LIKE模糊查询
    通配符’%
    SELECT * FROM employee 
            WHERE emp_name LIKE 'eg%';

    通配符’_
    SELECT * FROM employee 
            WHERE emp_name LIKE 'al__';

小练习

  1. 查看岗位是teacher的员工姓名、年龄
  2. 查看岗位是teacher且年龄大于30岁的员工姓名、年龄
  3. 查看岗位是teacher且薪资在9000-1000范围内的员工姓名、年龄、薪资
  4. 查看岗位描述不为NULL的员工信息
  5. 查看岗位是teacher且薪资是10000或9000或30000的员工姓名、年龄、薪资
  6. 查看岗位是teacher且薪资不是10000或9000或30000的员工姓名、年龄、薪资
  7. 查看岗位是teacher且名字是'大'开头的员工姓名、年薪

group by

单独使用GROUP BY关键字分组
    SELECT post FROM employee GROUP BY post;
    注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数

GROUP BY关键字和GROUP_CONCAT()函数一起使用
    SELECT post,GROUP_CONCAT(emp_name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名
    SELECT post,GROUP_CONCAT(emp_name) as emp_members FROM employee GROUP BY post;

GROUP BY与聚合函数一起使用
    select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人

强调: 如果我们用unique的字段作为分组的依据则每一条记录自成一组这种分组没有意义 多条记录之间的某个字段值相同,该字段通常用来作为分组的依据

聚合函数

##强调:聚合函数聚合的是组的内容,若是没有分组,则默认一组

示例:
    SELECT COUNT(*) FROM employee;
    SELECT COUNT(*) FROM employee WHERE depart_id=1;
    SELECT MAX(salary) FROM employee;
    SELECT MIN(salary) FROM employee;
    SELECT AVG(salary) FROM employee;
    SELECT SUM(salary) FROM employee;
    SELECT SUM(salary) FROM employee WHERE depart_id=3;

小练习

  1. 查询岗位名以及岗位包含的所有员工名字
  2. 查询岗位名以及各岗位内包含的员工个数
  3. 查询公司内男员工和女员工的个数
  4. 查询岗位名以及各岗位的平均薪资
  5. 查询岗位名以及各岗位的最高薪资
  6. 查询岗位名以及各岗位的最低薪资
  7. 查询男员工与男员工的平均薪资,女员工与女员工的平均薪资

HAVING过滤

HAVING与WHERE不一样的地方在于! 执行优先级从高到低where > group by > having  

  1. Where 发生在分组group by之前因而Where中可以有任意字段但是绝对不能使用聚合函数。
  2. Having发生在分组group by之后因而Having中可以使用分组的字段无法直接取到其他字段,可以使用聚合函数
MariaDB [db2]> select * from employee where salary > 100000;
+----+----------+------+-----+------------+---------+--------------+------------+--------+-----------+
| id | emp_name | sex  | age | hire_date  | post    | post_comment | salary     | office | depart_id |
+----+----------+------+-----+------------+---------+--------------+------------+--------+-----------+
|  2 | 蓝莓     | male |  78 | 2015-03-02 | teacher | NULL         | 1000000.31 |    401 |         1 |
+----+----------+------+-----+------------+---------+--------------+------------+--------+-----------+
1 row in set (0.00 sec)

MariaDB [db2]> select post,group_concat(emp_name) from employee group by post having salary > 10000;
ERROR 1054 (42S22): Unknown column 'salary' in 'having clause'
MariaDB [db2]> select post,group_concat(emp_name) from employee group by post having avg(salary) > 10000;
+-----------+------------------------------------------------------------+
| post      | group_concat(emp_name)                                     |
+-----------+------------------------------------------------------------+
| operation | 葡式蛋塔,绿茶布丁,鲜奶吐司,西米露,慕斯                     |
| teacher   | 红提,青提,葡萄,覆盆子,桑葚,黑莓,蓝莓,草莓                  |
+-----------+------------------------------------------------------------+
2 rows in set (0.00 sec)

小练习

  1. 查询各岗位内包含的员工个数小于2的岗位名、岗位内包含员工名字、个数
  2. 查询各岗位平均薪资大于10000的岗位名、平均工资
  3. 查询各岗位平均薪资大于10000且小于20000的岗位名、平均工资

ORDER BY 查询排序

按单列排序
    SELECT * FROM employee ORDER BY salary;
    SELECT * FROM employee ORDER BY salary ASC;
    SELECT * FROM employee ORDER BY salary DESC;

按多列排序:先按照age排序,如果年纪相同,则按照薪资排序
    SELECT * from employee
        ORDER BY age,
        salary DESC;

小练习

  1. 查询所有员工信息先按照age升序排序如果age相同则按照hire_date降序排序
  2. 查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资升序排列
  3. 查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资降序排列

LIMIT 限制查询的记录数

示例:
    SELECT * FROM employee ORDER BY salary DESC 
        LIMIT 3;                    #默认初始位置为0 
    
    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 0,5; #从第0开始,即先查询出第一条,然后包含这一条在内往后查5

    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 5,5; #从第5开始,即先查询出第6条,然后包含这一条在内往后查5

使用正则表达式查询

SELECT * FROM employee WHERE emp_name REGEXP '^ale';

SELECT * FROM employee WHERE emp_name REGEXP 'on$';

SELECT * FROM employee WHERE emp_name REGEXP 'm{2}';


小结:对字符串匹配的方式
WHERE emp_name = 'egon';
WHERE emp_name LIKE 'yua%';
WHERE emp_name REGEXP 'on$';

多表连接查询

创建表格

create table department(
id int,
name varchar(20) 
)engine=innodb default charset=utf8;

create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
)engine=innodb default charset=utf8;

##插入数据
insert into department values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');

insert into employee(name,sex,age,dep_id) values
('草莓','male',18,200),
('蓝莓','female',48,201),
('黑莓','male',38,201),
('桑葚','female',28,202),
('覆盆子','male',18,200),
('葡萄','female',18,204)
;

mysql> select * from department;
+------+----------+
| id   | name     |
+------+----------+
|  200 | 技术     |
|  201 | 人力资源 |
|  202 | 销售     |
|  203 | 运营     |
+------+----------+
4 rows in set (0.00 sec)

mysql> select * from employee;
+----+--------+--------+------+--------+
| id | name   | sex    | age  | dep_id |
+----+--------+--------+------+--------+
|  1 | 草莓   | male   |   18 |    200 |
|  2 | 蓝莓   | female |   48 |    201 |
|  3 | 黑莓   | male   |   38 |    201 |
|  4 | 桑葚   | female |   28 |    202 |
|  5 | 覆盆子 | male   |   18 |    200 |
|  6 | 葡萄   | female |   18 |    204 |
+----+--------+--------+------+--------+
6 rows in set (0.00 sec)

重点:外链接语法

SELECT 字段列表

    FROM 1 INNER|LEFT|RIGHT JOIN 2

    ON 1.字段 = 2.字段;
  1. 交叉连接: 不适用任何匹配条件,生成笛卡尔积
MariaDB [db3]> select * from employee,department;
+----+-----------+--------+------+--------+------+--------------+
| id | name      | sex    | age  | dep_id | id   | name         |
+----+-----------+--------+------+--------+------+--------------+
|  1 | 草莓      | male   |   18 |    200 |  200 | 技术         |
|  1 | 草莓      | male   |   18 |    200 |  201 | 人力资源     |
|  1 | 草莓      | male   |   18 |    200 |  202 | 销售         |
|  1 | 草莓      | male   |   18 |    200 |  203 | 运营         |
|  2 | 蓝莓      | female |   48 |    201 |  200 | 技术         |
|  2 | 蓝莓      | female |   48 |    201 |  201 | 人力资源     |
|  2 | 蓝莓      | female |   48 |    201 |  202 | 销售         |
|  2 | 蓝莓      | female |   48 |    201 |  203 | 运营         |
|  3 | 黑莓      | male   |   38 |    201 |  200 | 技术         |
|  3 | 黑莓      | male   |   38 |    201 |  201 | 人力资源     |
|  3 | 黑莓      | male   |   38 |    201 |  202 | 销售         |
|  3 | 黑莓      | male   |   38 |    201 |  203 | 运营         |
|  4 | 桑葚      | female |   28 |    202 |  200 | 技术         |
|  4 | 桑葚      | female |   28 |    202 |  201 | 人力资源     |
|  4 | 桑葚      | female |   28 |    202 |  202 | 销售         |
|  4 | 桑葚      | female |   28 |    202 |  203 | 运营         |
|  5 | 覆盆子    | male   |   18 |    200 |  200 | 技术         |
|  5 | 覆盆子    | male   |   18 |    200 |  201 | 人力资源     |
|  5 | 覆盆子    | male   |   18 |    200 |  202 | 销售         |
|  5 | 覆盆子    | male   |   18 |    200 |  203 | 运营         |
|  6 | 葡萄      | female |   18 |    204 |  200 | 技术         |
|  6 | 葡萄      | female |   18 |    204 |  201 | 人力资源     |
|  6 | 葡萄      | female |   18 |    204 |  202 | 销售         |
|  6 | 葡萄      | female |   18 |    204 |  203 | 运营         |
+----+-----------+--------+------+--------+------+--------------+
24 rows in set (0.00 sec)
  1. 内连接: 只连接匹配的行
##找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果
##department没有204这个部门,因而employee表中关于204这条员工信息没有匹配出来
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; 
+----+-----------+------+--------+--------------+
| id | name      | age  | sex    | name         |
+----+-----------+------+--------+--------------+
|  1 | 草莓      |   18 | male   | 技术         |
|  2 | 蓝莓      |   48 | female | 人力资源     |
|  3 | 黑莓      |   38 | male   | 人力资源     |
|  4 | 桑葚      |   28 | female | 销售         |
|  5 | 覆盆子    |   18 | male   | 技术         |
+----+-----------+------+--------+--------------+
5 rows in set (0.01 sec)

##上述sql等同于
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;
  1. 外连接之左连接: 优先显示左表全部记录

以左表为准,即找出所有员工信息,当然包括没有部门的员工 本质就是:在内连接的基础上增加左边有右边没有的结果

MariaDB [db3]> select employee.id,employee.name,department.name as depart_name from employee left join  department on employee.dep_id=department.id;
+----+-----------+--------------+
| id | name      | depart_name  |
+----+-----------+--------------+
|  1 | 草莓      | 技术         |
|  5 | 覆盆子    | 技术         |
|  2 | 蓝莓      | 人力资源     |
|  3 | 黑莓      | 人力资源     |
|  4 | 桑葚      | 销售         |
|  6 | 葡萄      | NULL         |
+----+-----------+--------------+
6 rows in set (0.00 sec)
  1. 外连接之右连接: 优先显示右表全部记录

以右表为准,即找出所有部门信息,包括没有员工的部门 本质就是:在内连接的基础上增加右边有左边没有的结果

MariaDB [db3]> select employee.id,employee.name,department.name as depart_name from employee right join  department on employee.dep_id=department.id;
+------+-----------+--------------+
| id   | name      | depart_name  |
+------+-----------+--------------+
|    1 | 草莓      | 技术         |
|    2 | 蓝莓      | 人力资源     |
|    3 | 黑莓      | 人力资源     |
|    4 | 桑葚      | 销售         |
|    5 | 覆盆子    | 技术         |
| NULL | NULL      | 运营         |
+------+-----------+--------------+
6 rows in set (0.00 sec)
  1. 全外连接: 显示左右两个表全部记录

全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果 注意mysql不支持全外连接 full JOIN 强调mysql可以使用此种方式间接实现全外连接

mysql> select * from employee left join department on employee.dep_id = department.id union select * from employee right join department on employee.dep_id = department.id;
+------+--------+--------+------+--------+------+----------+
| id   | name   | sex    | age  | dep_id | id   | name     |
+------+--------+--------+------+--------+------+----------+
|    1 | 草莓   | male   |   18 |    200 |  200 | 技术     |
|    5 | 覆盆子 | male   |   18 |    200 |  200 | 技术     |
|    2 | 蓝莓   | female |   48 |    201 |  201 | 人力资源 |
|    3 | 黑莓   | male   |   38 |    201 |  201 | 人力资源 |
|    4 | 桑葚   | female |   28 |    202 |  202 | 销售     |
|    6 | 葡萄   | female |   18 |    204 | NULL | NULL     |
| NULL | NULL   | NULL   | NULL |   NULL |  203 | 运营     |
+------+--------+--------+------+--------+------+----------+
7 rows in set (0.00 sec)

注意 union与union all的区别union会去掉相同的纪录

符合条件连接查询

示例1以内连接的方式查询employee和department表并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门

mysql> select employee.name,department.name from employee inner join department on employee.dep_id = department.id where age > 25;
+------+----------+
| name | name     |
+------+----------+
| 蓝莓 | 人力资源 |
| 黑莓 | 人力资源 |
| 桑葚 | 销售     |
+------+----------+
3 rows in set (0.00 sec)

示例2以内连接的方式查询employee和department表并且以age字段的升序方式显示

mysql> select employee.id,employee.name,employee.age,department.name from employee,department where employee.dep_id = department.id and age > 25 order by age asc;
+----+------+------+----------+
| id | name | age  | name     |
+----+------+------+----------+
|  4 | 桑葚 |   28 | 销售     |
|  3 | 黑莓 |   38 | 人力资源 |
|  2 | 蓝莓 |   48 | 人力资源 |
+----+------+------+----------+
3 rows in set (0.00 sec)

子查询

  1. 子查询是将一个查询语句嵌套在另一个查询语句中。
  2. 内层查询语句的查询结果,可以为外层查询语句提供查询条件。
  3. 子查询中可以包含IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
  4. 还可以包含比较运算符:= 、 !=、> 、<等

带IN关键字的子查询

select id,name from department
where id in
(select dep_id from employee group by dep_id having avg(age) > 25);

+------+----------+
| id   | name     |
+------+----------+
|  201 | 人力资源 |
|  202 | 销售     |
+------+----------+
2 rows in set (0.00 sec)

带比较运算符的子查询 EXISTS关字键字表示存在。在使用EXISTS关键字时内层查询语句不返回查询的记录。 而是返回一个真假值。True或False 当返回True时外层查询语句将进行查询当返回值为False时外层查询语句不进行查询 department表中存在dept_id=203Ture

MariaDB [db3]> select * from employee
    -> where exists
    -> (select id from department where id=200);
+----+-----------+--------+------+--------+
| id | name      | sex    | age  | dep_id |
+----+-----------+--------+------+--------+
|  1 | 草莓      | male   |   18 |    200 |
|  2 | 蓝莓      | female |   48 |    201 |
|  3 | 黑莓      | male   |   38 |    201 |
|  4 | 桑葚      | female |   28 |    202 |
|  5 | 覆盆子    | male   |   18 |    200 |
|  6 | 葡萄      | female |   18 |    204 |
+----+-----------+--------+------+--------+
6 rows in set (0.00 sec)

department表中不存在dept_id=205False

MariaDB [db3]> select * from employee where exists (select id from department where id=205);
Empty set (0.01 sec)

练习:查询每个部门最新入职的那位员工

MariaDB [db4]> SELECT * FROM employee AS t1 INNER JOIN (SELECT post, max(hire_date) max_date FROM employee GROUP BY post ) AS t2 ON t1.post = t2.post WHERE t1.hire_date = t2.max_date;
+----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+-----------+------------+
| id | name   | sex    | age | hire_date  | post      | post_comment | salary   | office | depart_id | post      | max_date   |
+----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+-----------+------------+
|  1 | 草莓   | male   |  18 | 2017-03-01 | teacher   | NULL         |  7300.33 |    401 |         1 | teacher   | 2017-03-01 |
| 13 | 甜椒   | female |  28 | 2017-01-27 | sale      | NULL         |  4000.33 |    402 |         2 | sale      | 2017-01-27 |
| 14 | 慕斯   | male   |  28 | 2016-03-11 | operation | NULL         | 10000.13 |    403 |         3 | operation | 2016-03-11 |
+----+--------+--------+-----+------------+-----------+--------------+----------+--------+-----------+-----------+------------+
3 rows in set (0.00 sec)