MySQL
Mysql 数据库
1.数据库概念:
之前所学,数据都要永久保存,比如用户注册的用户信息都是保存于文件中,而文件只能存在于某一台机器上。
如果我们不考虑从文件中读取数据的效率问题,并且假设我们的程序所有的组件都运行在一台机器上,那么用文件存取数据并没有问题。但是需要考虑的问题是:程序的执行效率依赖于承载它的硬件,而一台机器的性能能总归是有限的,受限于目前的硬件水平,垂直扩展是有极限的,于是我们只能通过水平扩展来增强我们系统的整体性能,这就需要我们将程序的各个组件分布于多台机器去执行。
需要注意的是,虽然我们将程序的各个组件分布到各台机器,单个组件仍然是一个整体,言外之意所有组件的数据还是要共享的,但每台机器上的组件都只能操作本机的文件,这就导致了数据必然不一致。
于是我们想到了将数据与程序分离:把文件存放于一台机器然后将多台机器通过网络去访问这台机器上的文件,即共享这台机器上的文件,共享则意味着竞争,会发生数据不安全,需要加锁处理。
为了远程访问并处理这台共享机器上的文件,我们必须为我们的程序额外写一段代码,完成如下功能:
#1.远程连接
#2.打开文件
#3.读写(加锁)
#4.关闭文件
我们写任何程序都需要有这段代码,于是我们提取这段代码,写成一个专门的处理软件,这就是mysql等数据库管理软件的由来,但mysql解决的不仅仅是数据共享的问题,还有查询效率,安全性等一系列问题,总之,把程序员从数据管理中解脱出来,专注于自己的程序逻辑的编写。
2.数据库概述:
什么是数据:描述事物的符号记录,描述事物的符号既可以是数字,也可以是文字、图片声音等,数据有多种表现形式,它们都可以经过数字化后存入计算机。
什么是数据库?(DataBase,简称DB)
数据库,顾名思义就是存放数据的仓库,只不过这个仓库是在计算机存储设备上。
数据库中的数据按一定的数据模型组织、描述和存储,具有较小的冗余度,较高的数据独立性和易扩展性,并可为各种用户共享。
什么是数据库管理系统(DataBase Management System 简称DBMS)
在了解了Data与DB的概念后,如何科学地组织和存储数据,如何高效获取和维护数据成了关键
这就用到了一个系统软件---数据库管理系统
如MySQL、Oracle、SQLite、Access、MS SQL Server
mysql主要用于大型门户,例如搜狗、新浪等,它主要的优势就是开放源代码,因为开放源代码这个数据库是免费的,他现在是甲骨文公司的产品。
oracle主要用于银行、铁路、飞机场等。该数据库功能强大,软件费用高。也是甲骨文公司的产品。
sql server是微软公司的产品,主要应用于大中型企业,如联想、方正等。
数据库说白了就是文件夹
数据库管理系统就是一个软件
数据库服务器:就是对外专门提供数据的一个机器
数据库服务器,数据库管理系统,表与记录的关系(重点理解)
表:student,scholl,class_list(即文件)
数据库:lzsh_info(即文件夹)
数据库管理系统:如mysql(是一个软件)
数据库服务器:一台计算机(对内存要求比较高)
总结:
数据库服务器---运行--->数据库管理软件
数据库管理软件--->管理--->数据库
数据库---组织--->表,即文件夹---组织--->文件
表---存放--->多条记录,即文件---存放--->多行内容
Mysql介绍:
Mysql是一个关系型数据库管理系统,在 WEB 应用方面MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
mysql是什么?
mysql就是一个socekt服务端
客户端软件
mysql自带
python模块
其他类型的数据库:
sqllite,db2,oracle,access,sql server,MySQL
分两大类:
关系型:上面这一坨,注意:sql语句通用(关系型:彼此之间有约束或者有联系)
非关系型:mongodb,redis,memcache
创建数据库:
数据库命名规则:
可以由字母、数字、下划线、@、#、$
区分大小写
唯一性
不能使用关键字如 create select
不能单独使用数字
最长128位
create database db1
数据库相关操作
数据库的相关操作
注意:数据库就相当于文件夹
表就相当于文件
数据库的命名规则:
一.数据库的增删改查(sql语句)
增:create database db1;
删:drop database db1;
改:alter database db1 charset utf8
查:show databases;#查看所有的数据库
show create database db1;查看指定的数据库
设置默认的utf8,在配置文件中:写上character_set_server = utf8
use db2 #代表你鼠标双击切换目录
select database() #查看你当前在哪个文件夹
二.表的增删改查
增:create table t1(id int ,name char); (t1.frm 表结构 ,t1.ibd 表数据)
删:drop table t1;
改:
插入数据:insert into test(id,name) values(1,'x')
不写给谁传值就指定都传,而且还是按照位置传
查:show tables; #查看所有表
show create table t1;#查看指定的表
select * from t1 #查看表数据
select id,name from t1 #查看表数据
engine = InnoDB
表的存储引擎是InnoDB
六、什么是存储引擎?
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方
法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)
SQL 解析器、SQL 优化器、缓冲池、存储引擎等组件在每个数据库中都存在,但不是每 个数据库都有这么多存储引擎。MySQL 的插件式存储引擎可以让存储引擎层的开发人员设 计他们希望的存储层,例如,有的应用需要满足事务的要求,有的应用则不需要对事务有这 么强的要求 ;有的希望数据能持久存储,有的只希望放在内存中,临时并快速地提供对数据 的查询。
一种类型表明的是一种存储方式
存储引擎:就是表的类型,不同的类型就会对应不同的处理机制去处理他
事务:就是要么同时成功,要么同时不成功
使用存储引擎
方法1:建表时指定
存储引擎
1.create table t1(id int) engine = innodb 会出现2个文件
2.create table t2(id int) engine = myisam 会出现3个文件(速度比上面的快),但是我们还是用innodb存储
3.create table t3(id int) engine = memory 只有表结构没有表数据,是创建到内存中的
4.create table t4(id int) engine = blackhole 黑洞,吃数据(数据存进去就没有了,存进去就没有了)
方法2:在配置文件中指定默认的存储引擎
/etc/my.cnf
[mysqld]
default-storage-engine=INNODB
innodb_file_per_table=1
注意的几点:
1.如果你在cmd中书命令的时候,输入错了就用\c跳出
2.\s查看配置信息
表操作
创建表的完整语法:
# 语法:
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
);
# 注意:
1.在同一张表中,字段名不能相同
2.宽度和约束条件可选,字段名和类型是必须的。
3.最后一个字段后不能加逗号!!!
# 补充:
# 1.宽度指的是对存储数据的限制
create table info (name char);
insert into t1 values('xxoo');
'''
1.没有安全模式的数据库版本,能够存放数据但是指挥存进去一个j
2.最新数据库版本直接报错提示无法存储:Data too long for coulumn 'name'at row 1
'''
# 2.约束条件初识 >>> null 与 not null
create table t1(id int,name char not null); # 限定不可为空not null
insert into t1 values(1,'x'); # char默认为1位,正常存储
insert into t1 values(2,null); #报错,限定了了不可为空 null
# 总结: 类型与约束条件的区别
类型:限制字段必须以什么样的数据类型存储
约束条件:约束条件实在类型之外添加的一种额外的限制
数据类型:
整型
分类:TINYINT SMALLINT MEDIUMINT INT BIGINT
作用:存储年龄,等级,id,各种号码等
类型存储范围:参考图片
验证整形字段有无符号及范围
'''
mysql> crerte table t3(x tinyint);
mysql> insert into t3 values(128),(-129);
ERROR 1264 (22003): Out of range value for column 'x' at row 1
超出范围 tinyint 范围为正127,负128
mysql> desc t3;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| x | tinyint(4) | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
'''
'''
mysql> create table t4(x tinyint unsigned);
mysql> insert into t4 values(-1),(256);
ERROR 1264 (22003): Out of range value for column 'x' at row 1
报错 tinyint unsigned 无正负号概念,只能存0-最大值
mysql> desc t4;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| x | tinyint(3) unsigned | YES | | NULL | |
+-------+---------------------+------+-----+---------+-------+
'''
'''
mysql> create table t5(x int unsigned);
mysql> insert into t5 values(1234567890);
Query OK, 1 row affected (0.00 sec)
mysql> desc t5;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| x | int(10) unsigned | YES | | NULL | |
+-------+------------------+------+-----+---------+-------+
'''
疑问:类型后面的宽度是否改变字段存储的大小限制
mysql> create table t6(x int(8));
mysql> insert into t6 values(1234567890);
mysql> select * from t6;
+------------+
| x |
+------------+
| 1234567890 |
+------------+# 超过设定值正常显示
======================================================
mysql> create t7(x int(8) unsigned zerofill);
mysql> insert into t7 values(666);
mysql> select * from t7;
+----------+
| x |
+----------+
| 00000666 |
+----------+# 不够设定值用0 填充
强调:对于整型来说,数据类型后的宽度并不是存储限制,而是显示限制,所以在创建表时,如果字段采用的是整型字段,完全不需要指定显示宽度,默认的显示宽度足够显示完整当初存放的数据
严格模式补充:
设置char,tinyint,存储数据时超出他们的最大存储长度,发现数据也能正常存储进去,只是mysql帮我们自动截取了最大长度。但在实际情况下,我们应该经量减少数据库的操作,缓解数据库的压力,让他仅仅只管理数据即可,这样的情况下就需要设置安全模式
show variables like '%mode%'; #查看数据库配置中变量名包括mode的配置参数
#修改安全模式
set session # 仅在当前操作页面有效
set global # 全局有效
set global sql_mode = 'STRICT_TRANS_TABLES'
# 修改完之后退出当前客户端重新登录即可
浮点型
分类:FLOAT DOUBLE decimal
应用场景:身高,体重,薪资等
字段限制特点(5,3)前一位表示所有的位数,后一位表示小数个数
三者最大整数位和小数位对比:
# 存储限制
float(255,30)
double(255,30)
decimal(65,30)
# 精确度验证
mysql> create table b1(x float(255,30));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into b1 values(1.11111111111111111111111111111);
Query OK, 1 row affected (0.00 sec)
mysql> select * from b1;
+----------------------------------+
| x |
+----------------------------------+
| 1.111111164093017600000000000000 |
+----------------------------------+ # 精确度较差
=================================================
mysql> create table b2(x double(255,30));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into b2 values(1.1111111111111111111111111111);
Query OK, 1 row affected (0.00 sec)
mysql> select * from b2;
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111200000000000000 |# 精确度较flort好
==========================================================
mysql> create table b3(x decimal(65,30));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into b3 values(1.11111111111111111111111111111);
Query OK, 1 row affected (0.00 sec)
mysql> select * from b3;
+----------------------------------+
| x |
+----------------------------------+
| 1.111111111111111111111111111110 |
+----------------------------------+ #精确度最优
字符类型
分类:char(定长)
varchar(变长)
作用:姓名,地址,描述类型信息等
create table a1(name char(4)) # 超出四个字符报错,不够四个字符补全
create table a2(name varchar(4)) #超出四个字符报错,不够四个有几个就存几个
# 验证存储限制:
# 验证存储限制
insert into t12 values('hello');
insert into t13 values('hello');
# 验证存储长度
insert into t12 values('a'); #'a '
insert into t13 values('a'); #'a'
select * from t12
select * from t13 # 无法查看真正的结果
select char_length(name) from t12
select char_length(name) from t13 # 仍然无法查看到真正的结果
"""首先应该肯定的是在硬盘上存的绝对是真正的数据,但显示的时候mysql会自动将末尾的空格取掉"""
# 如果不想让mysql帮你做自动去除末尾空格的操作,需要再添加一个模式
set global sql_mode="strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH";
# 退出客户端重新登陆
select char_length(x) from t12; #4
select char_length(y) from t13; #1
# 针对char类型,mysql在存储时会将数据用空格补全存放到硬盘中。但是会在读出结果的时候自动取掉末尾的空格
"""
char与varchar的使用区别
"""
name char(5)
# 缺点:浪费空间
# 优点:存取速度都快
egon alex lxx jxx txx
name varchar(5)
# 缺点:存取速度慢
# 优点:节省空间
1bytes+egon 1bytes+alex 1bytes+lxx 1bytes+jxx 1bytes+txx
时间类型
分类:
data: 2019-07-07
time: 7:07:07
Datetime: 2019-07-07 7:07:07
Year: 2019
测试:
create table lovers(
id int,
name char(16),
born_year year,
birth date,
study_time time,
reg_time datetime
);
insert into lovers values(1,'egon','2019','2019-05-09','11:11:00','2019-11-11 11:11:11');
mysql> select * from lovers;
+------+------------------+-----------+------------+------------+---------------------+
| id | name | born_year | birth | study_time | reg_time |
+------+------------------+-----------+------------+------------+---------------------+
| 1 | egon | 2019 | 2019-05-09 | 11:11:00 | 2019-11-11 11:11:11 |
+------+------------------+-----------+------------+------------+---------------------+
枚举与集合类型
-
分类
- 枚举enum 多选一
- 集合set 多选多
-
测试
create table user( id int, name char(16), gender enum('male','female','others') ); insert into user values(1,'jason','xxx') # 报错 insert into user values(2,'egon','female') # 正确! create table teacher( id int, name char(16), gender enum('male','female','others'), hobby set('read','sleep','sanna','dbj') ); insert into teacher values(1,'egon','male','read,sleep,dbj') # 集合也可以只存一个
约束条件
"""
PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录
FOREIGN KEY (FK) 标识该字段为该表的外键
NOT NULL 标识该字段不能为空
UNIQUE KEY (UK) 标识该字段的值是唯一的
AUTO_INCREMENT 标识该字段的值自动增长(整数类型,而且为主键)
DEFAULT 为该字段设置默认值
UNSIGNED 无符号
ZEROFILL 使用0填充
"""
not null+default
create table user(
id int,
name char(16)
);
insert into user values(1,null) # 可以修改
alter table user modify name char(16) not null;
insert into user(name,id) values(null,2); # 报错 插入数据可以在表名后面指定插入数据对应的字段
create table student(
id int,
name char(16) not null,
gender enum('male','female','others') default 'male' #设定默认值
)
insert into student(id,name) values(1,'jason') # 成功
unique
# 单列唯一
create table user1(
id int unique,
name char(16)
);
insert into user1 values(1,'jason'),(1,'egon') # 报错
insert into user1 values(1,'jason'),(2,'egon') # 成功
# 联合唯一
create table server(
id int,
ip char(16),
port int,
unique(ip,port)
)
insert into server values(1,'127.0.0.1',8080);
insert into server values(2,'127.0.0.1',8080); # 报错
insert into server values(1,'127.0.0.1',8081);
主键
primary key+auto_increment
# 单从约束角度来说primary key就等价于not null unique
create table t11(id int primary key);
desc t11;
insert into t11 values(1),(1); # 报错
insert into t11 values(1),(2);
# 除了约束之外,它还是innodb引擎组织数据的依据,提升查询效率
"""
强调:
1.一张表中必须有且只有一个主键,如果你没有设置主键,那么会从上到下搜索直到遇到一个非空且唯一的字段自动将其设置为主键
"""
create table t12(
id int,
name char(16),
age int not null unique,
addr char(16) not null unique
)engine=innodb;
desc t12;
"""
2.如果表里面没有指定任何的可以设置为主键的字段,那么innodb会采用自己默认的一个隐藏字段作为主键,隐藏意味着你在查询的时候无法根据这个主键字段加速查询了
索引:类似于书的目录,没有主键就相当于一页一页翻着查
3.一张表中通常都应该有一个id字段,并且通常将改id字段作成主键
"""
# 联合主键:多个字段联合起来作为表的一个主键,本质还是一个主键
create table t18(
ip char(16),
port int,
primary key(ip,port)
);
desc t18;
# 主键id作为数据的编号,每次最好能自动递增
create table t13(
id int primary key auto_increment,
name char(16)
);
insert into t13('jason'),('jason'),('jason'); # id字段自动从1开始递增
# 注意:auto_increment通常都是加在主键上,并且只能给设置为key的字段加
补充:
delete from tb1;
强调:上面的这条命令确实可以将表里的所有记录都删掉,但不会将id重置为0,
所以收该条命令根本不是用来清空表的,delete是用来删除表中某一些符合条件的记录
delete from tb1 where id > 10;
如果要清空表,使用truncate tb1;
作用:将整张表重置,id重新从0开始记录
外键
前戏之一对多关系
# 定义一张部门员工表
id name gender dep_name dep_desc
1 jason male 教学部 教书育人
2 egon male 外交部 漂泊游荡
3 tank male 教学部 教书育人
4 kevin male 教学部 教书育人
5 owen female 技术部 技术能力有限部门
"""
把所有数据都存放于一张表的弊端
1.组织结构不清晰
2.浪费硬盘空间
3.扩展性极差
"""
# 上述的弊端产生原因类似于把代码全部写在一个py文件中,你应该怎么做?>>>解耦合!将上述一张表拆成员工和部门两张表!
# 类似的表关系学生与班级,也是如此,一张学生表和一张班级表
# 分析表数据之间的关系:多个用户对应一个部门,一个部门对应多个用户。禁止一个用户对应多个部门这种情况是另外一张表关系
# 如何查找表与表之间的关系
"""
老师与课程表
1.站在老师表的角度:一名老师能否教授多门课程(限制死,不能,一名老师只能教python,不能同时教python和linux)
2.站在课程表的角度:一门课程能否可以被多个老师教,完全可以!
那就是课程表多对一老师表,如何表示这种关系?在课程表中创建一个字段(tea_id)指向老师表的id字段
学生与班级表
1.站在学生表的角度:???
2.站在班级表的角度:???
那就是学生表多对一班级表,如何表示这种关系?在学生表中创建一个字段(class_id)指向班级表的id字段
"""
# 再回过头来看员工与部门表,我员工表里面的dep_id我可以随意更改,但是应该有一个强制限制,限制dep_id字段必须只是部门表已有的id字段才合理
一对多(Foreign Key)
# foreign key会带来什么样的效果?
# 1、在创建表时,先建被关联的表dep,才能建关联表emp
create table dep(
id int primary key auto_increment,
dep_name char(10),
dep_comment char(60)
);
create table emp(
id int primary key auto_increment,
name char(16),
gender enum('male','female') not null default 'male',
dep_id int,
foreign key(dep_id) references dep(id)
);
# 2、在插入记录时,必须先插被关联的表dep,才能插关联表emp
insert into dep(dep_name,dep_comment) values
('sb教学部','sb辅导学生学习,教授python课程'),
('外交部','老男孩上海校区驻张江形象大使'),
('nb技术部','nb技术能力有限部门');
insert into emp(name,gender,dep_id) values
('alex','male',1),
('egon','male',2),
('lxx','male',1),
('wxx','male',1),
('wenzhou','female',3);
# 当我想修改emp里的dep_id或dep里面的id时返现都无法成功
# 当我想删除dep表的教学部的时候,也无法删除
# 方式1:先删除教学部对应的所有的员工,再删除教学部
# 方式2:受限于外键约束,导致操作数据变得非常复杂,能否有一张简单的方式,让我不需要考虑在操作目标表的时候还需要考虑关联表的情况,比如我删除部门,那么这个部门对应的员工就应该跟着立即清空
# 先把之前创建的表删除,先删员工表,再删部门表,最后按章下面的方式重新创建表关系
# 3.更新于删除都需要考虑到关联与被关联的关系>>>同步更新与同步删除
create table dep(
id int primary key auto_increment,
dep_name char(10),
dep_comment char(60)
);
create table emp(
id int primary key auto_increment,
name char(16),
gender enum('male','female') not null default 'male',
dep_id int,
foreign key(dep_id) references dep(id)
on update cascade
on delete cascade
);
insert into dep(dep_name,dep_comment) values
('sb教学部','sb辅导学生学习,教授python课程'),
('外交部','老男孩上海校区驻张江形象大使'),
('nb技术部','nb技术能力有限部门');
insert into emp(name,gender,dep_id) values
('alex','male',1),
('egon','male',2),
('lxx','male',1),
('wxx','male',1),
('wenzhou','female',3);
# 删除部门后,对应的部门里面的员工表数据对应删除
# 更新部门后,对应员工表中的标示部门的字段同步更新
多对多
# 图书表与作者表之间的关系
"""
仍然站在两张表的角度:
1.站在图书表:一本书可不可以有多个作者,可以!那就是书多对一作者
2.站在作者表:一个作者可不可以写多本书,可以!那就是作者多对一书
双方都能一条数据对应对方多条记录,这种关系就是多对多!
"""
# 先来想如何创建表?图书表需要有一个外键关联作者,作者也需要有一个外键字段关联图书。问题来了,先创建谁都不合适!如何解决?
# 建立第三张表,该表中有一个字段fk左表的id,还有一个字段是fk右表的id
create table author(
id int primary key auto_increment,
name char(16)
);
create table book(
id int primary key auto_increment,
bname char(16),
price int
);
insert into author(name) values
('egon'),
('alex'),
('wxx')
;
insert into book(bname,price) values
('python从入门到入土',200),
('葵花宝典切割到精通',800),
('九阴真经',500),
('九阳神功',100)
;
create table author2book(
id int primary key auto_increment,
author_id int,
book_id int,
foreign key(author_id) references author(id)
on update cascade
on delete cascade,
foreign key(book_id) references book(id)
on update cascade
on delete cascade
);
insert into author2book(author_id,book_id) values
(1,3),
(1,4),
(2,2),
(2,4),
(3,1),
(3,2),
(3,3),
(3,4);
一对一
客户表和学生表(老男孩的客户与学生之间,报名之前都是客户,只有报了名的才能是学生)
# 左表的一条记录唯一对应右表的一条记录,反之也一样
create table customer(
id int primary key auto_increment,
name char(20) not null,
qq char(10) not null,
phone char(16) not null
);
create table student(
id int primary key auto_increment,
class_name char(20) not null,
customer_id int unique, #该字段一定要是唯一的
foreign key(customer_id) references customer(id) #外键的字段一定要保证unique
on delete cascade
on update cascade
);
# 三种外键关系都是用foreign key,区别在于如何使用以及其他条件限制即可做出三种关系
修改表
# mysql对大小写不敏感!!!
语法:
1. 修改表名
ALTER TABLE 表名
RENAME 新表名;
2. 增加字段
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…],
ADD 字段名 数据类型 [完整性约束条件…];
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] FIRST;
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名;
3. 删除字段
ALTER TABLE 表名
DROP 字段名;
4. 修改字段 # modify只能改字段数据类型完整约束,不能改字段名,但是change可以!
ALTER TABLE 表名
MODIFY 字段名 数据类型 [完整性约束条件…];
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
复制表
# 查询语句执行的结果也是一张表,可以看成虚拟表
# 复制表结构+记录 (key不会复制: 主键、外键和索引)
create table new_service select * from service;
# 只复制表结构
select * from service where 1=2; //条件为假,查不到任何记录
create table new1_service select * from service where 1=2;
create table t4 like employees;
单表查询
前期表准备
create table emp(
id int not null unique auto_increment,
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
);
#插入记录
#三个部门:教学,销售,运营
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1), #以下是教学部
('egon','male',78,'20150302','teacher',1000000.31,401,1),
('kevin','male',81,'20130305','teacher',8300,401,1),
('tank','male',73,'20140701','teacher',3500,401,1),
('owen','male',28,'20121101','teacher',2100,401,1),
('jerry','female',18,'20110211','teacher',9000,401,1),
('nick','male',18,'19000301','teacher',30000,401,1),
('sean','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)
;
#ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk
1.语法执行顺序
# 初识查询语句
select id,name from emp where id >= 3 and id <= 6;
# 先后顺序
from
where
select
2.where约束条件
# 1.查询id大于等于3小于等于6的数据
select id,name from emp where id >= 3 and id <= 6;
select * from emp where id between 3 and 6;
# 2.查询薪资是20000或者18000或者17000的数据
select * from emp where salary = 20000 or salary = 18000 or salary = 17000;
select * from emp where salary in (20000,18000,17000); # 简写
# 3.查询员工姓名中包含o字母的员工姓名和薪资
# 在你刚开始接触mysql查询的时候,建议你按照查询的优先级顺序拼写出你的sql语句
"""
先是查哪张表 from emp
再是根据什么条件去查 where name like ‘%o%’
再是对查询出来的数据筛选展示部分 select name,salary
"""
select name,salary from emp where name like '%o%';
# 4.查询员工姓名是由四个字符组成的员工姓名与其薪资
select name,salary from emp where name like '____';
select name,salary from emp where char_length(name) = 4;
# 5.查询id小于3或者大于6的数据
select * from emp where id not between 3 and 6;
# 6.查询薪资不在20000,18000,17000范围的数据
select * from emp where salary not in (20000,18000,17000);
# 7.查询岗位描述为空的员工名与岗位名 针对null不能用等号,只能用is
select name,post from emp where post_comment = NULL; # 查询为空!
select name,post from emp where post_comment is NULL;
select name,post from emp where post_comment is not NULL;
3.group by
# 数据分组应用场景:每个部门的平均薪资,男女比例等
# 1.按部门分组
select * from emp group by post; # 分组后取出的是每个组的第一条数据
select id,name,sex from emp group by post; # 验证
"""
设置sql_mode为only_full_group_by,意味着以后但凡分组,只能取到分组的依据,
不应该在去取组里面的单个元素的值,那样的话分组就没有意义了,因为不分组就是对单个元素信息的随意获取
"""
set global sql_mode="strict_trans_tables,only_full_group_by";
# 重新链接客户端
select * from emp group by post; # 报错
select id,name,sex from emp group by post; # 报错
select post from emp group by post; # 获取部门信息
# 强调:只要分组了,就不能够再“直接”查找到单个数据信息了,只能获取到组名
# 2.获取每个部门的最高工资
# 以组为单位统计组内数据>>>聚合查询(聚集到一起合成为一个结果)
# 每个部门的最高工资
select post,max(salary) from emp group by post;
# 每个部门的最低工资
select post,min(salary) from emp group by post;
# 每个部门的平均工资
select post,avg(salary) from emp group by post;
# 每个部门的工资总和
select post,sum(salary) from emp group by post;
# 每个部门的人数
select post,count(id) from emp group by post;
# 3.查询分组之后的部门名称和每个部门下所有的学生姓名
# group_concat(分组之后用)不仅可以用来显示除分组外字段还有拼接字符串的作用
select post,group_concat(name) from emp group by post;
select post,group_concat(name,"_SB") from emp group by post;
select post,group_concat(name,": ",salary) from emp group by post;
select post,group_concat(salary) from emp group by post;
# 4.补充concat(不分组时用)拼接字符串达到更好的显示效果 as语法使用
select name as 姓名,salary as 薪资 from emp;
select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪资 from emp;
# 补充as语法 即可以给字段起别名也可以给表起
select emp.id,emp.name from emp as t1; # 报错 因为表名已经被你改成了t1
select t1.id,t1.name from emp as t1;
# 查询四则运算
# 查询每个人的年薪
select name,salary*12 as annual_salary from emp;
select name,salary*12 annual_salary from emp; # as可以省略
练习题
# 刚开始查询表,一定要按照最基本的步骤,先确定是哪张表,再确定查这张表也没有限制条件,再确定是否需要分类,最后再确定需要什么字段对应的信息
1. 查询岗位名以及岗位包含的所有员工名字
2. 查询岗位名以及各岗位内包含的员工个数
3. 查询公司内男员工和女员工的个数
4. 查询岗位名以及各岗位的平均薪资
5. 查询岗位名以及各岗位的最高薪资
6. 查询岗位名以及各岗位的最低薪资
7. 查询男员工与男员工的平均薪资,女员工与女员工的平均薪资
"""
参考答案:
select post,group_concat(name) from emp group by post;
select post,count(id) from emp group by post;
select sex,count(id) from employee group by sex;
select post,avg(salary) from emp group by post;
select post,max(salary) from employee group by post;
select post,min(salary) from employee group by post;
select sex,avg(salary) from employee group by sex;
"""
# 关键字where group by同时出现的情况下,group by必须在where之后
# where先对整张表进行一次筛选,如何group by再对筛选过后的表进行分组
# 如何验证where是在group by之前执行而不是之后 利用聚合函数 因为聚合函数只能在分组之后才能使用
select id,name,age from emp where max(salary) > 3000; # 报错!
select max(salary) from emp;
# 正常运行,不分组意味着每一个人都是一组,等运行到max(salary)的时候已经经过where,group by操作了,只不过我们都没有写这些条件
# 语法顺序
select
from
where
group by
# 再识执行顺序
from
where
group by
select
8、统计各部门年龄在30岁以上的员工平均工资
select post,avg(salary) from emp where age > 30 group by post;
# 对where过滤出来的虚拟表进行一个分组
# 还不明白可以分步执行查看结构
select * from emp where age>30;
# 基于上面的虚拟表进行分组
select * from emp where age>=30 group by post;
4.having
截止目前已经学习的语法
select 查询字段1,查询字段2,... from 表名
where 过滤条件
group by分组依据
# 语法这么写,但是执行顺序却不一样
from
where
group by
select
having的语法格式与where一致,只不过having是在分组之后进行的过滤,即where虽然不能用聚合函数,但是having可以!
1、统计各部门年龄在30岁以上的员工平均工资,并且保留平均工资大于10000的部门
select post,avg(salary) from emp
where age >= 30
group by post
having avg(salary) > 10000;
# 如果不信你可以将having取掉,查看结果,对比即可验证having用法!
#强调:having必须在group by后面使用
select * from emp having avg(salary) > 10000; # 报错
5.distinct
# 对有重复的展示数据进行去重操作
select distinct post from emp;
6.order by
select * from emp order by salary asc; #默认升序排
select * from emp order by salary desc; #降序排
select * from emp order by age desc; #降序排
#先按照age降序排,在年轻相同的情况下再按照薪资升序排
select * from emp order by age desc,salary asc;
# 统计各部门年龄在10岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行排序
select post,avg(salary) from emp
where age > 10
group by post
having avg(salary) > 1000
order by avg(salary)
;
7.limit
# 限制展示条数
select * from emp limit 3;
# 查询工资最高的人的详细信息
select * from emp order by salary desc limit 1;
# 分页显示
select * from emp limit 0,5; # 第一个参数表示起始位置,第二个参数表示的是条数,不是索引位置
select * from emp limit 5,5;
8.正则
select * from emp where name regexp '^j.*(n|y)$';
多表查询
表创建
#建表
create table dep_1(
id int,
name varchar(20)
);
create table emp_1(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);
#插入数据
insert into dep_1 values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');
insert into emp_1(name,sex,age,dep_id) values
('jason','male',18,200),
('egon','female',48,201),
('kevin','male',38,201),
('nick','female',28,202),
('owen','male',18,200),
('jerry','female',18,204)
;
# 当初为什么我们要分表,就是为了方便管理,在硬盘上确实是多张表,但是到了内存中我们应该把他们再拼成一张表进行查询才合理
表查询
select * from emp,dep; # 左表一条记录与右表所有记录都对应一遍>>>笛卡尔积
# 将所有的数据都对应了一遍,虽然不合理但是其中有合理的数据,现在我们需要做的就是找出合理的数据
# 查询员工及所在部门的信息
select * from emp,dep where emp.dep_id = dep.id;
# 查询部门为技术部的员工及部门信息
select * from emp,dep where emp.dep_id = dep.id and dep.name = '技术';
# 将两张表关联到一起的操作,有专门对应的方法
# 1、内连接:只取两张表有对应关系的记录
select * from emp inner join dep on emp.dep_id = dep.id;
select * from emp inner join dep on emp.dep_id = dep.id
where dep.name = "技术";
# 2、左连接: 在内连接的基础上保留左表没有对应关系的记录
select * from emp left join dep on emp.dep_id = dep.id;
# 3、右连接: 在内连接的基础上保留右表没有对应关系的记录
select * from emp right join dep on emp.dep_id = dep.id;
# 4、全连接:在内连接的基础上保留左、右面表没有对应关系的的记录
select * from emp left join dep on emp.dep_id = dep.id
union
select * from emp right join dep on emp.dep_id = dep.id;
子查询
# 就是将一个查询语句的结果用括号括起来当作另外一个查询语句的条件去用
# 1.查询部门是技术或者人力资源的员工信息
"""
先获取技术部和人力资源部的id号,再去员工表里面根据前面的id筛选出符合要求的员工信息
"""
select * from emp where dep_id in (select id from dep where name = "技术" or name = "人力资源");
# 2.每个部门最新入职的员工 思路:先查每个部门最新入职的员工,再按部门对应上联表查询
select t1.id,t1.name,t1.hire_date,t1.post,t2.* from emp as t1
inner join
(select post,max(hire_date) as max_date from emp group by post) as t2
on t1.post = t2.post
where t1.hire_date = t2.max_date
;
"""
记住一个规律,表的查询结果可以作为其他表的查询条件,也可以通过其别名的方式把它作为一张虚拟表去跟其他表做关联查询
"""
select * from emp inner join dep on emp.dep_id = dep.id;
练习题
导出的sql语句代码
/*
数据导入:
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50624
Source Host : localhost
Source Database : sqlexam
Target Server Type : MySQL
Target Server Version : 50624
File Encoding : utf-8
Date: 10/21/2016 06:46:46 AM
*/
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`caption` varchar(32) NOT NULL,
PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT;
-- ----------------------------
-- Table structure for `course`
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(32) NOT NULL,
`teacher_id` int(11) NOT NULL,
PRIMARY KEY (`cid`),
KEY `fk_course_teacher` (`teacher_id`),
CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `course`
-- ----------------------------
BEGIN;
INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '体育', '3'), ('4', '美术', '2');
COMMIT;
-- ----------------------------
-- Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`student_id` int(11) NOT NULL,
`course_id` int(11) NOT NULL,
`num` int(11) NOT NULL,
PRIMARY KEY (`sid`),
KEY `fk_score_student` (`student_id`),
KEY `fk_score_course` (`course_id`),
CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `score`
-- ----------------------------
BEGIN;
INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87');
COMMIT;
-- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`gender` char(1) NOT NULL,
`class_id` int(11) NOT NULL,
`sname` varchar(32) NOT NULL,
PRIMARY KEY (`sid`),
KEY `fk_class` (`class_id`),
CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `student`
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '钢蛋'), ('3', '男', '1', '张三'), ('4', '男', '1', '张一'), ('5', '女', '1', '张二'), ('6', '男', '1', '张四'), ('7', '女', '2', '铁锤'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '刘三'), ('14', '男', '3', '刘一'), ('15', '女', '3', '刘二'), ('16', '男', '3', '刘四');
COMMIT;
-- ----------------------------
-- Table structure for `teacher`
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`tname` varchar(32) NOT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of `teacher`
-- ----------------------------
BEGIN;
INSERT INTO `teacher` VALUES ('1', '张磊老师'), ('2', '李平老师'), ('3', '刘海燕老师'), ('4', '朱云海老师'), ('5', '李杰老师');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
拷贝上述代码,新建一个.sql文件,保存到桌面
打开navicat新建数据库day41,选中新建的数据库鼠标右键选择运行SQL文件
弹出文件框,选中刚刚保存到桌面的.sql文件即可
练习题
1、查询所有的课程的名称以及对应的任课老师姓名
4、查询平均成绩大于八十分的同学的姓名和平均成绩
7、 查询没有报李平老师课的学生姓名
8、 查询没有同时选修物理课程和体育课程的学生姓名
9、 查询挂科超过两门(包括两门)的学生姓名和班级
# 参考答案
#1、查询所有的课程的名称以及对应的任课老师姓名
SELECT
course.cname,
teacher.tname
FROM
course
INNER JOIN teacher ON course.teacher_id = teacher.tid;
#4、查询平均成绩大于八十分的同学的姓名和平均成绩
SELECT
student.sname,
t1.avg_num
FROM
student
INNER JOIN (
SELECT
student_id,(
avg(num) AS avg_num
FROM
score
GROUP BY
student_id
HAVING
avg(num) > 80
) AS t1 ON student.sid = t1.student_id;
#7、 查询没有报李平老师课的学生姓名(找出报名李平老师课程的学生,然后取反就可以)
SELECT
student.sname
FROM
student
WHERE
sid NOT IN (
SELECT DISTINCT
student_id
FROM
score
WHERE
course_id IN (
SELECT
course.cid
FROM
course
INNER JOIN teacher ON course.teacher_id = teacher.tid
WHERE
teacher.tname = '李平老师'
)
);
#8、 查询没有同时选修物理课程和体育课程的学生姓名(没有同时选修指的是选修了一门的,思路是得到物理+体育课程的学生信息表,然后基于学生分组,统计count(课程)=1)
SELECT
student.sname
FROM
student
WHERE
sid IN (
SELECT
student_id
FROM
score
WHERE
course_id IN (
SELECT
cid
FROM
course
WHERE
cname = '物理'
OR cname = '体育'
)
GROUP BY
student_id
HAVING
COUNT(course_id) = 1
);
# 9、 查询挂科超过两门(包括两门)的学生姓名和班级
select student.sname,class.caption from class INNER JOIN student
on class.cid = student.class_id
WHERE student.sid in
(select student_id from score where num < 60
GROUP BY student_id
HAVING COUNT(course_id) >=2)
;
pymysql模块
# 1.安装:pip3 insatll pymysql
# 2.代码链接
import pymysql
#链接
conn=pymysql.connect(
host='localhost',
user='root',
password='123',
database='egon',
charset='utf8')
#游标
cursor=conn.cursor() #执行完毕返回的结果集默认以元组显示
#cursor=conn.cursor(cursor=pymysql.cursors.DictCursor) # 以字典的方式显示数据
# 3.pymysql操作数据库
#执行sql语句
user = input(">>>:").strip()
pwd = input(">>>:").strip()
sql='select * from userinfo where name="%s" and password="%s"' %(user,pwd) #注意%s需要加引号
rows=cursor.execute(sql) #执行sql语句,返回sql查询成功的记录数目
# 获取真实数据cursor.fetchone(),cursor.fetchall(),cursor.fetchmany(),类似管道取值,获取一条,所有,多条
cursor.scroll(1,'relative') # 相对移动
cursor.scroll(3,'absolute') # 绝对移动
cursor.close()
conn.close()
sql注入问题
# 不要手动去拼接查询的sql语句
username = input(">>>:").strip()
password = input(">>>:").strip()
sql = "select * from user where username='%s' and password='%s'"%(username,password)
# 用户名正确
username >>>: jason' -- jjsakfjjdkjjkjs
# 用户名密码都不对的情况
username >>>: xxx' or 1=1 --asdjkdklqwjdjkjasdljad
password >>>: ''
增删改
# 增
sql = "insert into user(username,password) values(%s,%s)"
rows = cursor.excute(sql,('jason','123'))
# 修改
sql = "update user set username='jasonDSB' where id=1"
rows = cursor.excute(sql)
"""
增和改单单执行excute并不会真正影响到数据,需要再执行conn.commit()才可以完成真正的增改
"""
# 一次插入多行记录
res = cursor,excutemany(sql,[(),(),()]
"""
2、创建一个stu表,字段有:自增主键id,不为空姓名,默认值性别(枚举类型),无限制身高
3、为stu表依次插入以下三条数据
i)插入一条包含id,name,gender,height四个信息的数据
ii)插入一条name,gender,height三个信息的数据
iii)插入一条只有name信息的数据
4、实现新表new_stu对已有表stu的字段、约束及数据的拷贝
5、创建一张有姓名、年龄的teacher表,在最后添加工资字段,在姓名后添加id主键字段
6、思考:将5中id字段移到到表的最前方,形成最终字段顺序为id、姓名、年龄、工资
7、完成 公民表 与 国家表 的 多对一 表关系的创建
8、完成 学生表 与 课程表 的 多对多 表关系的创建
9、完成 作者表 与 作者简介表 的 一对一 表关系的创建(思考为什么要这样设计)
"""
"""
create table stu(
id int primary key not null auto_increment,
name char(32) not null,
gender enum('male','female') not null default 'male',
height int);
"""
"""
insert into stu values
(1,'stu1','male','180cm');
insert into stu(name,gender,height) values
('stu2','female','165cm');
insert into stu(name) values
('stu3');
"""
"""
create table people(
id int primary key not null auto_increment,
name char(32),
age tinyint unsigned,
gender enum('male','female') not null default 'male',
country_id,
foreign key(country_id) references country(id)
on update cascade
on delete cascade
);
"""
"""
create table student2course(
id int primary key not null auto_increment,
student_id int,
course_id int,
foreign key(student_id) references student(id)
on update cascade
on delete cascade,
foreign key(course_id) references course(id)
on update cascade
on delete cascade
);
"""
"""
insert into student2course(student_id,course_id) values
(1,2),
(1,3),
(1,4),
(2,2),
(2,3),
(3,1),
(3,2),
(4,2),
(4,4);
"""
"""
create table author_profile(
id int primary key not null auto_increment,
profile char(128),
author_id int unique,
foreign key(author_id) references author(id)
on update cascade
on delete cascade
);
"""
"""
create table emp(
id int not null unique auto_increment,
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
);
#插入记录
#三个部门:教学,销售,运营
insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('jason','male',18,'20170301','张江第一帅形象代言',7300.33,401,1), #以下是教学部
('egon','male',78,'20150302','teacher',1000000.31,401,1),
('kevin','male',81,'20130305','teacher',8300,401,1),
('tank','male',73,'20140701','teacher',3500,401,1),
('owen','male',28,'20121101','teacher',2100,401,1),
('jerry','female',18,'20110211','teacher',9000,401,1),
('nick','male',18,'19000301','teacher',30000,401,1),
('sean','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)
;
"""
"""
create table book(
id int primary key auto_increment,
name char(16),
price tinyint not null
);
create table author(
id int primary key auto_increment,
name char(16)
);
insert into book(name,price) values
('葵花宝典',88),
('九阴真经',78),
('辟邪剑谱',99);
insert into author(name) values
('张全蛋'),
('李诞'),
('寡人');
create table book_author(
id int primary key auto_increment,
book_id int ,
author_id int,
foreign key(book_id) references book(id)
on update cascade
on delete cascade,
foreign key(author_id) references author(id)
on update cascade
on delete cascade
);
insert into book_author(book_id,author_id) values
(1,1),
(1,2),
(1,3),
(2,1),
(2,3),
(3,2),
(3,2);
"""