第十章数据库

10.1.1 数据库存在的必要

  • 为什么会有数据库?

    • 很多功能如果只是操作文件来改变数据起非常繁琐的,程序员需要做很多事情

    • 对于多台机器或多个进程操作用一份数据,程序员自己解决并发和安全问题比较麻烦

    • 自己处理一下数据备份,容错的措施

  • 数据库的优势

    • c/s架构的 操作数据文件的一个管理文件

      • 帮助我们解决并发问题

      • 能够帮助我们用更简单更快速的方式完成数据的增删改查

      • 能够给我们提供一些容错、高可用的机制

      • 权限的认证

10.1.2数据库管理系统及分类

  • 数据库管理系统--专门用来管理数据文件,帮助用户更简洁的操作数据的软件

    • DBMS --server端

  • 数据--data

  • 文件

  • 文件夹 --数据库database db

  • 数据库管理员 - -DBA

  • 数据库服务器 --一台机器

  • 安装数据库

  • 数据库管理系统分类

    • 关系型数据库

      • mysql 开源的、没有那么严谨

        • 小公司 互联网公司

      • sql server

      • oracle 收费、比较严谨、安全性比较高

        • 国企 事业单位、银行 金融行业

      • sqllite

    • 非关系型数据库(存储速度快)

      • redis

      • mongodb

     

10.1.3mysql的cs架构

  • mysqld install 安装数据库服务

  • net start mysql 启动数据库的server端

  • 停止server:net stop mysql

  • 客户端可以是python代码也可以是一个程序

    • mysql.exe 是一个客户端

    • mysql -u 用户名 -p密码

  • mysql中的用户和权限

    • 在安装数据库之后,有一个最高权限的用户root

    • mysql server端的ip eva/123

    • mysql 192.168.12.87 eva/123

      • 链接:mysql -h192.168.12.87 - uroot -p123

  • 我们的mysql客户端不仅可以连接本地的数据库,也可以连接网络上的某一个数据库的server端

10.1.4mysql命令

  • select user(): 查看当前用户是谁

  • set password = password('密码') 设置密码

  • 创建用户

    • create user '21'@'192.168.12.%' identified by '123' 指示网段

    • 以别人的身份登录:mysql -us21 -p123 -h192.168.12.87

  • 查看文件夹

    • show databases;

  • 创建文件夹

    • create database + 文件名;

  • 授权

    • show grant for ’s21'@'192.168.12.%'

    • grant all on (+库,例如day37.,(.表示所有的文件)to 's21'@'192.168.12.%' (to后面加用户) ---授权

    • flush privileges;立即生效

    • 授权并创建用户

      • grant all on day37.* to 'alex'@'%' ' identified by '123'

10.2 创建 库 表

10.2.1 创建库

  • DDL定义语言:创建库 、创建表

    • 创建用户

      • create user '用户名'@'ip地址(192.168.12.%)'表明192.168.12.0网段的用户都可以使用这个用户名

      • create user '用户名'@'%' 表示网络可以通讯的所有ip地址都可以使用这个用户名

      • create user '用户名'@'网段(127.168.12.87)'表示只有一个ip地址可以使用这个用户名

    • 创建库

      • create database +库名

    • 创建表

      • create table 表名(字段名 数据类型(长度),)

  • DML操纵语句:存数据,删数据,修改数据,查看

    • 数据的增删改查

      • 增加 insert into

      • 删除 delete from

      • 改 update

      • 查 select

        • select user();查看当前用户

        • select database();查看当前所在的数据库

      • show

        • show databases; 查看当前的数据库

        • show tables;查看当前的库中有哪些表

      • desc +表名;查看表结构

      • use + 库名;切换到某个库下

  • DCL 控制权限:grant revoke

    • 给用户授权

      • grant + 要授予的权限 ( grant select/insert/all)

      • grant select on 库名.* to '用户名'@'ip地址/段' identified by ' 密码' (给用户授权)

         

  • 创建库 :create database +数据库名;

  • 查看当前有多少个数据库:show databases;

  • 查看当前使用的数据库是什么:select database();

  • 切换到这个库(文件夹)下面:use 数据库的名字;

  • 删库:drop database

10.2.2 创建表

  • 创建表

    • 先use某个库

    • create table +表的名字(字段名字);-->create table student(id int,name char(6)); char 字符,6表示长度

  • 查看当前文件夹中有多少张表:show tables;

  • 删除表

    • drop table +表名

  • 查看表结构:desc +表名;

  • 操作表中的数据

    • 数据的增加: insert into + 表名字+ values(1,'alex');例如:insert into student values(1,'alex');insert into student values(2,'wusir');

    • 数据的查看:select * from +表名字;

    • 修改数据:update 表名 set 字段名= 值 --》update student set name = 'yuan';--全改了;update student set name = 'wusir' where id =2;-->修改某一行(把表中id等于2的name改回wusir了)

    • 删除数据:delete from 表名字;-->整张表清空;删除某一行

      delete from 表名 where id=1;delete from student where id=1;

10.2.3mysql表的操作

  • 创建方式 存储 --存储引擎(innoDB,MyISAM,MEMORY)

  • 表的存储方式

    • 存储方式1:(MyISAM 5.5以下默认存储方式)

      • 存储的文件个数:表结构,表中的数据,索引

      • 支持表级锁

      • 不支持行级锁、事务、外键

    • 存储方式2:(innoDB 5.6以上默认存储方式)

      • 存储的文件个数:表结构,表中的数据

      • 支持行级锁:能给表中的某一行加锁,支持行级锁、表锁

      • 支持事务:把几句python代码变成一个不可拆分的原子型操作,要么一起成功,要么一起失败

      • 支持外键:外部链接,做数据关联,还有一些约束操作

    • 存储方式3:MEMORY内存

      • 存储的文件个数:表结构

      • 优势:增删改查特别快

      • 劣势:重启数据消失、容量有限

  • 索引:加速查找类似目录的 --数据库的目录

  • 查看配置项:

    • show variables like '%engine%'(想看的配置项)

  • 建表时之指定存储引擎

    • create table 表名(字段)engine = 存储引擎;

      • 例:create table t2 (id int,name char(4)) engine=myisam;

  • 查看表的结构:

    • show create table +表名 \G; :可以查看和这张表相关的所有信息 (\G格式整理)

    • desc 表名; 只能查看表的字段的基础信息

      • describe 表名 ;

  • 面试题

用什么数据库:mysql
版本是什么:5.6
都用这个版本吗:不一定,新项目可能用新的版本,其他的可能还是5.6
存储引擎:innoDB
为什么要用这个存储引擎:支持事务(支付的时候用得多)、外键、行级锁(能够更好的处理并发的修改问题)

10.3msql数据类型

10.3.1整数及小数表示

  • 整数

    • create table t1(id1 int(4),id2 int(11)); 有符号的表

      • 对于int的数据类型它能表示的数字范围不被宽度约束,只能约束数字的显示宽度

      • 默认的int是有符号的,想要没有符号的需要加上unsigned

    • create table t2(id1 int unsigned,id2 int(11));没有符号的表,没有符号的表示范围更大

  • 小数

    • float(255,30)255表示约束的是小数一共有多少位,30表示是小数点后的位数

    • double(255,30)255表示约束的是小数一共有多少位,30表示是小数点后的位数

    • 指定位数小数的表:create table t2(f1 float(5,2),d2 double(5,2));[整数三位,2位小数],小数位后超过了会保留小数会进行四舍五入

    • 不指定位数的表:create table t2(f1 float,d2 double);

      • float单精度 表示的小数点后的位数更少

      • double 双精度 表示的小数点后的位数更多

    • create table t2(d1 decimal,d2 decimal(25,20));

      • decimal后面不指定会取整

      • decimal 精准取

10.3.2日期和时间

  • date 年月日 create table t4 (d date,t time,dt datetime)

  • time 时分秒(跑步)

  • year 年份值(历史事件)

  • datetime 年月日时分秒

  • timestamp 混合日期和时间值,时间戳 --不能为空,并且有默认值

dt datetime (NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)
--可以插入的表的时候可以在建表的时候可以加入,这样以后每次更新都会自动生成时间
  • 例题
create table t4(y year,d date,dt datetime,ts timestamp)
insert into t4 values(now(),vow(),now(),now())

insert into t4 (y) values (2019);--只插入year的值

insert into t4 values(2019,20180701,20180701120000,20180702010100);---指定时间以数字的形式写
insert into t4 values(2019,'2018-07-01','2018-07-01 12:00:00','2018-07-02 01:01:00');-以字符串的形式写
mysql> create table t4 (d date,t time,dt datetime);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t4;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d     | date     | YES  |     | NULL    |       |
| t     | time     | YES  |     | NULL    |       |
| dt    | datetime | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
3 rows in set (0.01 sec)

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

mysql> select * from t4;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 |
+------------+----------+---------------------+
1 row in set (0.00 sec)

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

mysql> select * from t4;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 |
| NULL       | NULL     | NULL                |
+------------+----------+---------------------+
2 rows in set (0.00 sec)

10.3.3 字符串

  • char定长的单位

    • 例 char(15) alex(后面会补足空格直到15)

  • varchar 变长的单位

    • varchar(15) -- alex4 4表示alex的长度

  • 哪一个存储方式好?

    • varchar:节省空间、存取效率相对低

    • char:浪费空间,但是存取效率相对高, 长度变化小的

  • 手机号码、身份证号 char

  • 用户名、密码 char

  • 评论的时候 微博 说说 微信状态 varchar

create table t5(name1 char(5),name2 varchar(5));
insert into t5('alexander','alexander'); #超过长度放不全

insert into t5('a    ','a     ');

10.3.4ENUM 和set类型

  • enum 单选框

    • en = ENUME('male','female')

  • set 多选框

    • hobby set('running','sing','抽烟‘,'喝酒')

create table t6(name char(12), gender ENUME('male','female'),hobby set('running','sing','抽烟','喝酒'));
 insert into t6 values('alex','male','抽烟');
 insert into t6 values('alex','male','抽烟,喝酒');

10.4 表操作

10.4.1 约束

  • unsigned 设置某个数字无符号

  • not null 某一个字段不能为空

    • not null 不生效的解决方法

设置严格模式:
    不支持对not null字段插入null值
    不支持对自增长字段插入”值
    不支持text字段有默认值

直接在mysql中生效(重启失效):
mysql>set sql_mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";

配置文件添加(永久生效): 在配置文件my.ini里面添加
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
create table t1(id int not null,
                name char(12) not null,
                age int)
  • default 给某个字段设置默认值
create table t1(id int not null,
                name char(12) not null,
                gender enum('male','female' not null default 'male'));#不为空且默认值为male
insert into t1 values(1,'alex','male');
insert into t1(id,name) values(1,'alex');

unique 设置某一个字段不能重复

  • 有些不能设置为重复

  • mysql设置了unique,可以为空,且空可以重复

  • 设置unique的时候总是跟着不能为空

create table t2(id int unique,
                uesername char(12) unique,
               password char(18) );
insert into t2 values(1,'alex','alex3714');
  • 联合唯一
create table t3(id int unique,                ip char(15) unique,                        servername char(18) ,
   port int
   unique(ip,port)); #ip+port联合唯一,表中显示mul
insert into t3 values(1,'192.168.168.87','mysql''3306');

auto_increment:设置某一个int类型的字段,自动增加,只能有在数字类型上

  • 设置自增的字段必须是数字且必须是唯一的

  • auto_increment自带非空属性

  • 删除已经写入的数据,在往里面写数据是直接接着往下数的

create table t5(id int unique auto_increment,#非空唯一自增 
                username char(15) ,                        
password char(18)); insert into t2(username,password) values('alex','alex3714');

primary key:设置某一个字段非空且唯一 主键

  • 一张表只能设置一个主键

  • 一张表可以不设置主键

  • 一张表最好设置一个主键

  • 约束这个字段 非空(not null)+唯一(unique)

create table t6(id int not null unique,
                name char(12) not null unique);#指定的第一个非空且唯一的字段会被定义为主键,第二个不能生效
     
 create table t7(id int primary key,
               name char(12) not null unique );
insert into t7 values(1,'alex');
insert into t7 valuse(1,'wusir');#报错
  • 联合主键
create table t8(id int ,                
                ip ip char(15) ,                        
servername char(18) ,   port int, primary key(ip,port)); #ip+port联合主键insert into t8 values(1,'192.168.168.87','mysql','3306');

foreign key:外键

  • 涉及两张表

#部门表 pid postname postid post_comment(部门评论) post_phone

create table post(pid int primary key,
                  postname char(10) not null unique,
                  post_comment varchare(255),
                  post_phone char(11));

#员工表 id age gender salary hire_date post_id
create table staff(id int primary key auto_incream,
                   age int,
                   gender enum('male','female')
                   salary float(8,2)
                   hire_date date,
                  post_id int,
                  foreign key (post_id ) references post(pid));

关联的数据类型必须一致
要想在一张表中创建外键,创建外键的字段至少是unique,关联的是primary key
先创建外表,在创建关联外表
关联的值是无法利用update和delete修改和删除的

多级联删除和级联更新

create table staff(id int primary key auto_incream,
                   age int,
                   gender enum('male','female')
                   salary float(8,2)
                   hire_date date,
                  post_id int,
                  foreign key (post_id ) references post(pid) on update cascade on delete cascade);#这个字段会根据外表的变化变化

10.4.2 修改表操作

  • 不常用

  • 创建项目之前

  • 项目开发、运行过程中

#alter table 表名 add -- 添加字段
alter table 表名 add 字段名 数据类型(宽度)约束 first/after name 最前面添加或者在哪个后面添加

#alter table 表名 drop -- 删除字段
alter table 表名 drop 字段

#alter table 表名 modify -- 修改已经存在字段的宽度、约束
alter table 表名 modify 原来字段的名字 新的类型()#字段名字不能变

#alter table 表名 change -- 修改已经存在字段的宽度、约束、字段名字
alter table 表名 change name new_name 数据类型()约束

例题:
id name age 把age放在name前面
alter table 表名 modify age int not null after id;
alter table 表名 modify age int not null first;--放在最前面

10.4.3 表关系

表关系

  • 一对多或多对一: foreign key 永远是在多的那张表设置

    • 多个学生都是同一个班级的

  • 学生表 关联 班级表

    • 学生是多 班级是一

  • 关联的外键要是primary key,在多的一张表中创建外键

    • 插入数据的话是先往autho这张表中插入数据

#一对多或称为多对一
三张表:出版社,作者信息,书
  
  一对多(或多对一):一个出版社可以出版多本书
  
关联方式:foreign key
  
=====================多对一=====================
  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
  ('北京工业地雷出版社'),
  ('人民音乐不好听出版社'),
  ('知识产权没有用出版社')
  ;
  
  insert into book(name,press_id) values
  ('九阳神功',1),
  ('九阴真经',2),
  ('九阴白骨爪',2),
  ('独孤九剑',3),
  ('降龙十巴掌',2),
  ('葵花宝典',3)
  ;

一对一:foreign key +unique

  • 作为外键的字段要加unique(定义哪个字段是外键就加unique)

    • 插入数据时先往author这张表插入数据

  • 客户关系表:手机号码 招生老师 上次联系的时间 备注信息

  • 学生表:姓名 入学日期 缴费日期 结业

  • 后出现的那张表中的数据作为外键,并且要约束这个外键是唯一的

#一对一
两张表:学生表和客户表

一对一:一个学生是一个客户

关联方式:foreign key+unique

create table customer(
    -> id int primary key auto_increment,
    -> name varchar(20) not null,
    -> qq varchar(10) not null,
    -> phone char(16) not null
    -> );

create table student(
    -> id int primary key auto_increment,
    -> class_name varchar(20) not null,
    -> customer_id int unique, #该字段一定要是唯一的
    -> foreign key(customer_id) references customer(id) #外键的字段一定要保证unique
    -> on delete cascade
    -> on update cascade
    -> );

#增加客户
mysql> insert into customer(name,qq,phone) values
    -> ('韩蕾','31811231',13811341220),
    -> ('杨澜','123123123',15213146809),
    -> ('翁惠天','283818181',1867141331),
    -> ('杨宗河','283818181',1851143312),
    -> ('袁承明','888818181',1861243314),
    -> ('袁清','112312312',18811431230)

mysql> #增加学生
mysql> insert into student(class_name,customer_id) values
    -> ('脱产1班',3),
    -> ('周末1期',4),
    -> ('周末1期',5)
    -> ;

多对多:产生第三张表,把两个关联关系的字段作为第三张表的外键

  • 作者与书多对多:在自己的表中不建关系,而是在新建的第三张表建立外键关系

    • 插入数据时先往原来的两张表中插入数据,在往新建的表中插入数据

  • 作者

  • 出版社 和书

#多对多
三张表:出版社,作者信息,书

多对多:一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多
  
关联方式:foreign key+一张新的表

=====================多对多=====================
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('egon'),('alex'),('yuanhao'),('wpq');

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


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)
;
  • 注意:往表中插入数据:先往有外键关联的表中插入数据,再往所定的外键表中插入数据

  • 删除表: drop table 表名;

10.5 操作数据

10.5.1 增加

  • 所有的在这个表中的字段都需要安装顺序被填写这个这里---》insert into 表名 vallues (值。。。。)

  • 所有在字段位置填写了名字的字段和后面的值必须是一一对应---> insert into 表名(字段名,字段名....) values (值),(值),(值);

  • value 单数 一次性写入一行数据

  • values复数 一次性写入多行数据

  • 区分:

    • 写入一行内容还是写入多行

      • insert into 表名 vallue (字段)

      • insert into 表名 vallues (字段1)(字段1),(字段3),

    • 是把这一行所有的内容都写入

      • insert into 表名 vallue (字段)

    • 指定字段写入

                         insert into 表名(字段名1,字段名2....) values (值),(值),

insert into t1 value (1,'alex',83);#写入一行
insert into t1 values(1,'alex',83),(2,'wusir',68),。。。。;#写入多行
insert into t1(name,age) values('alex',83),('wusir',68),。。。。;

10.5.2 删除

  • delete

    • delete from 表 where 条件;

10.5.3 修改、更新

  • update

    • update 表名 set 字段=新值 where 条件;

10.5.4 单表查询

  • select

    • select *from 表

    • select 字段,字段。。from表

    • select distanct 字段,字段。。from 表 --按查出来的去重

    • select 字段*+-/数字 from 表---四则运算

    • select 字段 新名字 from 表 ---重命名字段

    • select 字段 as 新名字,字段 as 新名字 from 表 ---重命名字段

    • select concat ('姓名:', name ---根据什么拼接

    • case

    • select 字段1 ,字段2 from 表名 where 条件;

10.6 表的查询

10.6.1 单表查询where 语句

  • 比较运算

>  <  =  >=  <=  !=  <>

范围筛选

  • 多选一
select * from 表名 where 字段 in(值1,值2,值3....);

#只打印部分
select 字段1,字段2 表名 where 字段 in(值1,值2,值3....);

在一个模糊的范围里

  • 在一个数值区间

select * from 表名 where 字段 between 值1 and 值2;
  • 字符串的模糊查询 like
select * from 表名  where 字段 like '程%'; 以程开头
select 字段 from 表名  where 字段 like '程%'; 
select * from 表名  where 字段 like '程_'; _表示一个字符
select * from 表名  where 字段 like '%n'; 以n结尾
select * from 表名  where 字段 like '%n%'; 含n

* % 通配符:匹配任意长度的内容,%的位置可以放在前表示以什么开头,也可以放在后面表示以什么结尾,
也可以放在中间表示匹配前面长度的任意内容和匹配后面长度任意内容
* _ 通配符:匹配一个字符长度的任意内容
  • 正则匹配 regexp 更加细腻的匹配
select * from 表 where 字段 regexp 正则表达式
select * from 表 where 字段 regexp '^j[a-z]{5}';

逻辑运算 - 条件拼接

  • 与 and

  • 或 or

  • 非 not

select * from 表名 where 字段 not in(值1,值2,值3....);

身份运算符 关于null 只能用is null/not null

select * from 表名  where 字段 is not null
select * from 表名  where 字段 is null

10.6.2group by 分组

会把在group by 后面的这个字段,每一个不同的项都保留下来,并且把值是这一项的所有行归为一组,会显示这个组中第一个人的信息,一组只显示一项

select * from 表名 group by 字段; 会显示第一个

10.6.3聚合

  • 定义:把很多行的同一个字段经一些统计,最终得到一个结果

  • count (字段) 统计这个字段有多少项

select count(*) from 表名;  整张表中的数据
select count(字段) from 表名; 为空不计算,不为空的计算
  • sun(字段) 统计这个字段对应的数值的和
select sun(*) from 表名; 
select sun(字段) from 表名;
  • avg(字段) 统计这个字段对应的数值的平均值
select avg(*) from 表名; 
select avg(字段) from 表名;
  • min(字段)
select 字段,min(字段) from 表;
select 字段,min(字段) from 表 group by 字段;
  • max(字段)
  • 求部门的最高薪资或者求公司的最高薪资都可以通过聚合函数查到,但是要得到对应的人就必须通过多表查询

select 字段,max(字段) from 表;--》不准
select 字段,max(字段) from 表 group by 字段;

10.6.4 分组聚合

  • 总是根据会重复的项来分组

  • 分组总是会和聚合函数一起用 最大 最小 平均 求和 有多少项

select 字段, count(*/字段) from 表 group by 字段;#前后两个字段要相同

#例题  求各个组的人数
select count(*) from employee group by post;

#求各部门的平均薪资
select post,avg(salary) from employee group by post;
#求各部门的平均年龄
select post,avg(age) from employee group by post;
#求各部门年龄最小的
select post,min(age) from employee group by post;
#求最晚入职的
select  max(hire_date) from employee;
#求最早入职的
select  min(hire_date) from employee;
#求各部门最晚入职的
select  post,man(hire_date) from employee post;
#最晚入职的男女
select  sex,man(hire_date) from employee sex;

10.6.5having+ 条件

  • 和group by一起用

  • 过滤 组

  • 执行顺序总是先执行where 在执行group by分组,所以相关先分组之后在根据分组做某些条件筛选的时候where都用不上,只能用having 来完成

#部门人数大于3的部门
select  post  from employee group by post having count(*)>3;
#平均薪资大于一万的部门
select post from employee group by post having avg(salary)>10000;

select * from employee having age>18; 必须要有age字段

10.6.6 order by 排序

跟什么字段排序

  • order by 字段; 默认升序排列asc,从小到大

  • order by 字段 desc ; 指定降序排列desc 从大到小

  • order by 第一个字段 asc,第二个字段 desc;指定先根据第一个字段升序排列,在第一个字段相同的情况下,在根据第二个字段排列

select * from employee order by salary;-默认从小到大排
select * from employee order by salary desc;-降序排
select * from employee order by age,order by salary desc;优先根据age排序,在根据salary降序排
#薪资在前3的
select * from employee order by salary desc limit 3;

10.6.7 limit

  • 去前n个 limit n ==limit 0,n;

  • 分页 limit m,n 从m+1 可以取nge

  • limit n offset m == limit m,n 从m+1开始取n个

#薪资在前3的
select * from employee order by salary desc limit 3;

员工展示的网页:18的员工,每页展示5个员工
从n+1开始取

select * from employee order by salary desc limit 0,5;从第一个开始取1-5
select * from employee order by salary desc limit 6,5;6-5
select * from employee order by salary desc limit 10,5;11-15
select * from employee order by salary desc limit 15,5;16-18

总结

  • select distinct 需要显示的列 from 表

  • select distinct 需要显示的列 from 表 where 条件

  • select 需要显示的列 from 表 group by 分组 (一般情况用了group by就不用distinct了)

  • select distinct 需要显示的列 from 表 having 过滤组条件

  • select distinct 需要显示的列 from 表 order by 排序

  • select distinct 需要显示的列 from 表 limit 前n条

  • 执行顺序:from--where--group by --having--select--order by--limit

  • 越在前面缩小范围,后面执行的越快

10.7 多表查询

10.7.1 连表查询

  • 连接的语法

select 字段 from 表1 left/right/inner join 表2 on 表1.字段 = 表2.字段;
  • 两张表是怎么连在一起的,一行会对应后面表的每一行--笛卡尔积 select * from 表1,表2;

  • 把两张表连在一起查

  • 外连接

    • 左外连接 left join 常用

      • 左表不管有没有匹配上都显示(永远显示全量的左表中的数据),而右表匹配不上的不显示

select * from 表1 left join 表2 on 表1.字段=表2.字段;

             右外连接 right join

                  永远显示全量的右表中的数据),而左表匹配不上的不显示

select * from 表1 right join 表2 on 表1.字段=表2.字段;

        全外连接 union

              mysql中没有全外连接的语法

select * from 表1 right join 表2 on 表1.字段=表2.字段 union select * from 表1 left join 表2 on 表1.字段=表2.字段;

内连接 inner join 常用

  • 两张表条件不匹配的项不出现在内连接的结果中

select * from 表1 inner join 表2 on 表1.字段=表2.字段;

例题:找技术部的所有人姓名

方式一:
select emp.name from emp inner join department on emp.dep_id = department.id where department.name = '技术';
方式二:
select emp.name from emp inner join department as dep on emp.dep_id = dep.id where dep.name = '技术';
方式三:
select emp.name from emp inner join department d on emp.dep_id = d.id where d.name = '技术';

例题: 找出年龄大于25岁的员工以及员工所在的部门名称

select emp.name,d.name from emp inner join department as d on emp.dep_id = d.id where age >25;  不重复的时候可以不用写表名

根据age的升序顺序来连表查询

select * from emp inner join department as d on emp.dep_id = d.id order by age;

10.7.2 子查询

找到技术部和销售部门所有人的姓名
#方法一
先找到技术部门和销售部门的部门id
select id from department where name = '技术' or name = '销售';
找到emp表中的部门id=200或者202的人名

select name from emp where dep_id in (select id from department where name = '技术' or name = '销售');
#方法二
select emp.name from emp inner join department on emp_id = department.id where department.name in('技术''销售');
  • 优先使用连表查询,因为连表查询的效率高

  • 带in关键字的子查询

#查询平均年龄在25岁以上的部门名
结果在哪张表查的就是哪张表
select id,name from department
    where id in 
        (select dep_id from employee group by dep_id having avg(age) > 25);

#查看技术部员工姓名
select name from employee
    where dep_id in 
        (select id from department where name='技术');

#查看不足1人的部门名(子查询得到的是有人的部门id)
select name from department where id not in (select distinct dep_id from employee);

#查询大于所以人平均年龄的员工名和年龄
select * from employee where age>(select avg(age) from employee);

#查询大于部门内平均年龄的员工名、年龄
select * from employee inner join (select dep_id,avg(age) as avg_age from employee gruop by dep_id ) as d employee.dep_id = d.dep_id where employee.age>d.avg_age;

带EXISTS关键字的子查询

  • EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。 而是返回一个真假值。True或False 当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询

#department表中存在dept_id=203,Ture
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=200);
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  2 | alex       | female |   48 |    201 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
+----+------------+--------+------+--------+

#department表中存在dept_id=205,False
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=204);
Empty set (0.00 sec)

10.8 索引

10.8.1 索引原理

  • 什么是索引

    • 就是建立起一个在存储表阶段就有的一个存储结构能在查询的时候加速

  • 索引的重要性

    • 读写比例是:10:1

    • 读(查询)的速度至关重要

  • 索引的原理

    • block 磁盘预读原理

      • 4096个字节

    • 读硬盘的io操作是时间非常长,比cpu执行指令的时间长很多

    • 尽量的减少io次数才是读写数据的主要要解决的问题

    • 数据库的存储方式:

      • 新的数据结构---树

      • 平衡树 balance tree -b树

      • 在b树的基础上静下来改良 -- b+树

        • 分支节点和根节点都不再存储实际的数据了

          • 让分支和根节点能存储更多的索引的信息就降低了树的高度,所有的实际数据都存储在叶子节点中

        • 在叶子节点之间加入了双向的链式结构方便在查询中的范围条件

      • mysql中所有的b+树索引的高度都基本都控制在3层

        • io操作的次数非常稳定

        • 利于通过范围查询

      • 什么会影响索引的效率--树的高度

        • 什么会影响树的高度

          • 对哪一列创建索引,选择尽量短的列做索引

          • 要对区分度高的列建索引,重复率超过了10%那么不适合创建索引

  • 聚集索引和辅助索引

    • 聚集索引 -主键:数据之间存储在树结构的叶子节点(更快)

    • 辅助索引 - 除了主键之外所有的索引都是辅助索引:数据不直接存储在树中,只存储相关的数据,还需要通过至少一次才能找到想要的值,还有回表的过程 稍慢

    • 在innodb中 聚集索引和辅助索引并存的,在myisam中只有辅助索引没有聚集索引

  • 索引的种类

    • primary key 主键 自动创建索引 --聚集索引 约束的作用:非空+唯一

      • 联合主键

    • unique 自带索引 --辅助索引 约束的作用:唯一

      • 联合唯一

    • index 辅助索引 没有约束作用

      • 联合索引:可以根据两个字段创建

  • 创建索引

create index 索引名字 on 表(字段)
drop index 索引名 on 表名 --删除
  • create index 索引名字 on 表(字段)
    drop index 索引名 on 表名 --删除
  • 索引是如何发挥作用的

    • select * from 表 where id= xxxxx;

      • 在id字段没有索引的时候效率低

      • 在id字段有索引了之后效率高

10.8.2正确的使用索引

  • id作为条件的时候

    • 如果不加索引,速度慢

    • 加了索引,速度快

  • 查询的字段不适合索引的字段,速度也慢

  • 索引不生效的原因

    • 要查询的数据的范围大

      • '> < >= <= !='

      • between and

        • select * from 表 where id between 值1 and 值2;推荐

        • select * from 表 order by id limit 值1,值2;不推荐

      • like

        • 结果的范围大,索引不生效

        • 如果是abc%索引生效,%abc索引就不生效

    • 如果一列内容的区分度不高,索引也不生效

      • name 列

    • 索引列不能在条件中参与计算

      • select * from s1 where id*10 =100000;索引不生效

      • select * from s1 where id =100000/10;索引生效

    • 对两列内容进行条件的查询

      • and :and条件两端的内容会优先现在一个有索引的,并且树形结构更好的,来进行查询

        • 两个条件都成立才能完成where条件,先完成范围小的缩小后面条件的压力

        • select * from s1 where id = 100000 and email = 'eva100000@oldboy';id不是索引,emali是索引

      • or:or条件的,不会进行优化,只是根据条件从左到右依次筛选,条件中带有or的要想命中索引,这些条件中所有的列都是索引列

        • select * from s1 where id = 100000 and email = 'eva100000@oldboy';id不是索引,emali是索引

    • 联合索引(对id和email建立联合索引)

create index ind_mix on s1(id,email)
    • select * from s1 where id = 100000 and email = 'eva100000@oldboy';--快

      • 联合索引中如果使用了or条件索引就不能生效

        • select * from s1 where id = 100000 and email = 'eva100000@oldboy';--慢

      • 最左前缀原则:在联合索引中条件必须含有在创建索引的时候的第一个索引列即创建索引时的第一个字段

        • select * from s1 where id = 100000 ;快,能命中索引

        • select * from s1 where email = 'eva100000@oldboy'; 慢,不能命中索引

      • 在整个条件中,从开始出现模糊匹配的那一刻,索引就失效了

        • select * from s1 where id > 100000 and email = 'eva10000@oldboy';不能命中索引

        • select * from s1 where id = 100000 and like *eva%';

  • 什么时候用联合索引

    • 只对a 对abc条件进行索引,而不是

    • 对b,对c经常单列的索引

  • 对于单列索引

    • 选择一个区分度高的列建立索引,条件的番外尽量小,条件中的列不要参与计算,使用and作为条件的连接符

  • 使用or来连接多个条件

    • 在满足上述条件的基础上,对or相关的所以列分别创建索引

  • 索引使用的其他注意事项

 避免使用select *
- 使用count(*)
- 创建表时尽量使用 char 代替 varchar
- 表的字段顺序固定长度的字段优先
- 组合索引代替多个单列索引(由于mysql中每次只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引)
- 尽量使用短索引
- 使用连接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致
- 索引散列值(重复少)不适合建索引,例:性别不适合
  • 覆盖索引

    • 如果我们使用索引作为条件查询,查询完毕之后,不需要回表查,这就是覆盖索引

    • 要查询的字段和条件都是同一个字段时就可以用覆盖索引

    • explain select id from s1 where = 10000;---覆盖索引

    • explain select id from s1 where id> 10000;---覆盖索引

  • 执行计划:如果想在执行sql之前就想知道sql语句的执行情况,那么可以使用执行计划

    • 情况1:数据非常多的时候,查询需要很多时间,利用explain +sql语句--并不会真的执行sql,而是会给你列出一个执行计划,看是否符合你的预期

    • 情况2:数据比价少,但是将来数据会增多很多,考虑到未来的情况,利用利用explain +sql语句看是否符合预期

  • 合并索引:对两个字段分别创建索引,由于sql的条件让两个索引同时生效了,那么这个时候这两个索引就成为了合并索引

10.8.3 索引总结

  • 原理和概念

    • b树

    • b+树

    • 聚集索引--innodb

    • 辅助索引--innodb myisam

  • sql索引的创建(单个,联合)、删除

  • 索引的命中:范围,条件的字段是否参与计算(不能用函数),列的区分度,列的长度,条件and/or,联合索引的最左前缀问题

  • 一些名词

    • 覆盖索引

    • 合并索引

  • explain执行计划

  • 建表、使用sql语句的时候注意的

    • char 代替 varchar

    • 连表 代替 子查询

    • 创建表的时候 固定长度的字段放在前面

 

10.9 数据备份和恢复

10.9.1 数据备份

要先退出,在输入命令行才能备份

#语法:
# mysqldump -h 服务器 -u用户名 -p密码 数据库名 > (路径)备份文件名.sql

#示例:
#单库备份
mysqldump -uroot -p123 db1 > db1.sql --备份数据库
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql --备份指定表
导入备份的时候需要先建库

#多库备份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

#备份所有库
mysqldump -uroot -p123 --all-databases > all.sql 

#导入备份的数据
source  备份的数据的路径

10.9.2 数据恢复

#方法一:
[root@egon backup]# mysql -uroot -p123 < /backup/all.sql

#方法二:
mysql> use db1;
mysql> SET SQL_LOG_BIN=0;   #关闭二进制日志,只对当前session生效
mysql> source /root/db1.sql

10.10 事务和锁

begin;  # 开启事务
select * from emp where id = 1 for update;  # 查询id值,for update添加行锁;对查出的这些行即将要修改的数据加锁
update emp set salary=10000 where id = 1; # 完成更新
commit; # 提交事务

10.11 sql 注入

导致数据库不安全

  • 输入用户名,密码

  • 用户名和密码到数据库里查询

    • 如果能查到数据,说明用户名和密码正确

    • 如果查不到,就说明用户名或密码错误

select * from 表 where name = '数据' and password = '数据';
  • 在sql 里面的-- 表示注释掉--之后的语句
select * from 表 where name = '数据' ;-- and password = '数据';--这样用户名对了就可以密码无所谓

select * from 表 where name = '201585' or 1=1 ;-- and password = '数据';--输入的用户名和密码都无所谓

避免sql注入

  • 在execute里面拼

import pymysql
conn = pymysql.connect(host = '127.0.0.1',user = 'root',password = '123',database='day41')
cur = conn.cursor()
username = input('user>>>')
password = input('passwd>>')
sql = 'select * from userinfo where name =%s and password = %s'
cur.execute(sql,(username,password)) #执行sql语句
print(cur.fetchone())#该方法获取下一个查询结果集。结果集是一个对象
cur.close()
conn.close()

fetchone():接收全部的返回结果行

猜你喜欢

转载自www.cnblogs.com/xu1296634150/p/12726996.html