数据库知识
数据库
day37 数据库基本知识
1.数据库概念
#数据库
# 很多功能如果只是通过操作文件来改变数据是非常繁琐的
# 程序员需要做很多事情
# 对于多台机器或者多个进程操作用一份数据
# 程序员自己解决并发和安全问题比较麻烦
# 自己处理一些数据备份,容错的措施
# C/S架构的 操作数据文件的一个管理软件
# 1.帮助我们解决并发问题
# 2.能够帮助我们用更简单更快速的方式完成数据的增删改查
# 3.能够给我们提供一些容错、高可用的机制
# 4.权限的认证
# 数据库管理系统 —— 专门用来管理数据文件,帮助用户更简洁的操作数据的软件
# DBMS
# 数据 data
# 文件
# 文件夹 -- 数据库database db
# 数据库管理员 —— DBA
# 数据库管理系统
关系型数据库
# sql server
# oracle 收费、比较严谨、安全性比较高
# 国企 事业单位
# 银行 金融行业
# mysql 开源的
# 小公司
# 互联网公司
# sqllite
非关系型数据库 #【查快递,一个快递单号,后面跟了很多信息】
# redis
# mongodb
2.数据库基本命令
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 安装mysql遇到的问题
# 操作系统的问题
# 缺失dll文件
# 安装路径
# 不能有空格
# 不能有中文
# 不能带着有转义的特殊字符开头的文件夹名
# 安装之后发现配置有问题
# 再修改配置往往不能生效
# 卸载之后重装
# mysqld remove
# 把所有的配置、环境变量修改到正确的样子
# 重启计算机 - 清空注册表
# 再重新安装
****************************************分割线******************************
# mysql的CS架构
# mysqld install 安装数据库服务
# net start mysql 启动数据库的server端
# 停止server net stop mysql
# 客户端可以是python代码也可以是一个程序
# mysql.exe是一个客户端
# mysql -u用户名 -p密码
# mysql中的用户和权限
# 在安装数据库之后,有一个最高权限的用户root
# mysql 192.168.12.87 eva/123
# mysql -h192.168.12.87 -uroot -p123
# 我们的mysql客户端不仅可以连接本地的数据库
# 也可以连接网络上的某一个数据库的server端
# select user();
查看当前用户是谁
# set password = password('密码')
设置密码
# 创建用户
create user 's21'@'192.168.12.%' identified by '123';
mysql -us21 -p123 -h192.168.12.87
# 授权
grant all on day37.* to 's21'@'192.168.12.%';
# 授权并创建用户
grant all on day37.* to 'alex'@'%' identified by '123';
# 查看文件夹
# show databases;
# 创建文件夹
# create database day37;
# 库 表 数据
DDL数据库定义语言 ;创建库、创建表
DML数据库操纵语句;存数据,删除数据,修改数据,查看
DCL控制权限;grant/revoke
# 库
create database 数据库名; # 创建库
show databases; # 查看当前有多少个数据库
select database();# 查看当前使用的数据库
use 数据库的名字; # 切换到这个数据库(文件夹)下
# 表操作
查看当前文件夹中有多少张表
# show tables;
创建表
# create table student(id int,name char(4));
删除表
# drop table student;
查看表结构
# desc 表名;
# 操作表中的数据
数据的增加
# insert into student values (1,'alex');
# insert into student values (2,'wusir');
数据的查看
# select * from student;
修改数据
# update 表 set 字段名=值
# update student set name = 'yuan';
# update student set name = 'wusir' where id=2;
删除数据
# delete from 表名字;
# delete from student where id=1;
# 把创建用户,给用户授权,登陆一下同桌的mysql server,给同桌开一个账号
# 操作库 表 数据
day 38 数据库数据类型
1.内容回顾
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 数据库
# 关系型数据库 :mysql oracle sqlserver sqllite
# 非关系型数据库 :mongodb redis
# sql :
# ddl 定义语言
# 创建用户
# create user '用户名'@'%' 表示网络可以通讯的所有ip地址都可以使用这个用户名
# create user '用户名'@'192.168.12.%' 表示192.168.12.0网段的用户可以使用这个用户名
# create user '用户名'@'192.168.12.87' 表示只有一个ip地址可以使用这个用户名
# 创建库
# create database day38;
# 创建表
# create table 表名(字段名 数据类型(长度),字段名 数据类型(长度),)
# dml 操作语言
# 数据的
# 增 insert into
# 删 delete from
# 改 update
# 查 select
# select user(); 查看当前用户
# select database(); 查看当前所在的数据库
# show
# show databases: 查看当前的数据库有哪些
# show tables;查看当前的库中有哪些表
# desc 表名;查看表结构
# use 库名;切换到这个库下
# dcl 控制语言
# 给用户授权
# grant select on 库名.* to '用户名'@'ip地址/段' identified by '密码'
# grant select,insert
# grant all
2.今日内容
# mysql的表的操作
# 创建方式 存储 —— 存储引擎
# 基础数据类型
# 表的约束
# 创建表
# 查看表结构
# 修改表
# 删除表
3.习题讲解
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 有一个文件,这个文件中有20001行数据,开启一个线程池,为每100行创建一个任务,打印这100行数据。
from copy import copy
def print_line(lines):
print(lines)
from concurrent.futures import ThreadPoolExecutor
tp = ThreadPoolExecutor(20) # 起一个线程池
with open('file',encoding='utf-8') as f:
lines = []
for line in f:
if len(lines) == 100:
tp.submit(print_line,copy(lines)) #读是一个线程,打印是20个线程,读的时候实现并发
lines.clear()
lines.append(line)
if lines:
tp.submit(print_line, copy(lines))
============================== 分割线======================================
# 1. print 和 文件的读 写 都是io操作,
# 这个题主要就是起线程在一个线程读文件的时候,利用这个线程读取文件的时间交给另一个线程来进行打印操作
# 2. 使用线程可以有效的规避掉io操作的时间,提高程序的的效率
# 3.解耦程序的功能
# 4.默认参数是列表
4.表的存储引擎
# 表的存储方式
# 存储方式1:MyISAM 5.5以下 默认存储方式
存储的文件个数:表结构、表中的数据、索引
支持 表级锁
不支持 行级锁 不支持事务 不支持外键
# 存储方式2:InnoDB 5.6以上 默认存储方式
适合处理并发
存储的文件个数:表结构、表中的数据
支持 行级锁、支持表级锁
【在修改一行数据的时候,别的用户可以获取】
支持 事务
支持 外键
# 存储方式3: MEMORY 内存
存储的文件个数:表结构
优势 :增删改查都很快
劣势 :重启数据消失、容量有限
# 索引 - 数据库的目录
===============================分割线===================================
# 查看配置项:
show variables like '%engine%';
# 创建表
create table t1 (id int,name char(4));
create table t2 (id int,name char(4)) engine=myisam;
create table t3 (id int,name char(4)) engine=memory;
# 查看表的结构
show create table 表名; 能够看到和这张表相关的所有信息
desc 表名 只能查看表的字段的基础信息
# describe 表名
面试题
# 公司用什么数据库 : mysql
# 版本是什么 :5.6
# 都用这个版本么 :不是都用这个版本
# 存储引擎 :innodb
# 为什么要用这个存储引擎:(它是默认引擎)
# 支持事务 支持外键 支持行级锁
# 能够更好的处理并发的修改问题
5.数据类型--数字
# 整数 int
# create table t4 (id1 int(4),id2 int(11));
int默认是有符号的
它能表示的数字的范围不被宽度约束
它只能约束数字的显示宽度
# create table t5 (id1 int unsigned,id2 int);
# 小数 float
# create table t6 (f1 float(5,2),d1 double(5,2));
# create table t7 (f1 float,d1 double);
# create table t8 (d1 decimal,d2 decimal(25,20));
6.数据类型--时间
# 类型
year 年
date 年月日
time 时分秒
datetime、timestamp 年月日时分秒
# create table t9(
# y year,d date,
# dt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
# ts timestamp);
7.数据类型--字符串
# char(15) 定长的单位
# alex alex
# alex
# varchar(15) 变长的单位
# alex alex4
# 哪一个存储方式好?
# varchar :节省空间、存取效率相对低
# char :浪费空间,存取效率相对高 长度变化小的
# 手机号码、身份证号 char
# 用户名、密码 char
# 评论 微博 说说 微信状态 varchar
# create table t11 (name1 char(5),name2 varchar(5));
8.其他数据类型--ENUM和SET类型
# enum 枚举 set 集合
create table t12(name char(12),gender enum('male','female'),hobby set('抽烟','喝酒','烫头','洗脚'));
# insert into t12 values('alex','不详','抽烟,喝酒,洗脚,洗脚,按摩');
ENUM只允许从值集合中选取单个值,而不能一次取多个值。
set类型可以允许值集合中任意选择1或多个元素进行组合。对超出范围的内容将不允许注入,而对重复的值将进行自动去重。
day39 约束、表操作、数据操作
1.内容回顾
#!/usr/bin/env python
# -*- coding:utf-8 -*-
查看引擎:show create table s1
# 存储引擎
# myisam :适合做读 插入数据比较频繁的,对修改和删除涉及少的,不支持事务、行级锁和外键。有表级锁
# 索引和数据分开存储的,mysql5.5以下默认的存储引擎
# 3个文件
# innodb :适合并发比较高的,对事务一致性要求高的,
# 相对更适应频繁的修改和删除操作,有行级锁,外键且支持事务
# 索引和数据是存在一起的,mysql5.6以上默认的存储引擎
# 2个文件
# memory :数据存在内存中,表结构存在硬盘上,查询速度快,重启数据丢失
# 数据类型
# 数字类型 :int,float(5,2)
# 字符串类型 :char(10),varchar(10) 10 最大不超过是个字符
# 时间类型:datetime,date,time
# enum和set:enum(单选项1,单选项2),set(多选项1,多选项2)
# create table 表名(
# 字段名 数据类型(宽度/选项),
# 字段名 数据类型(宽度/选项),
# )
# 创建库
# create database day39
# 查看有哪些库
# show databases;
# 查看当前所在的数据库
# select database();
# 切换库
# use 库名
# mysql支持的函数
# database(),user(),now(),concat(),password()
# create table staff (
# id int,
# name char(12),
# gender enum('male','female'),
# hire_date date,
# salary float(8,2),
# hobby set('唱','跳','rap','打篮球'))
2.今日内容
# 操作表
# 约束
# 修改表结构
# 删除表
# drop table 表名;
# 操作数据
# 插入数据
# 修改数据
# 删除数据
# 查找数据
# 单表查
# 多表查
3.约束
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 约束
# unsigned 设置某一个数字无符号 【约束 int 】
# not null 某一个字段不能为空 【严格模式会影响非空设置的效果,非空可能不生效】
# default 给某个字段设置默认值 【一般与enum()结合】
# unique 设置某一个字段不能重复
# 联合唯一
# unique(字段1,字段2)
# auto_increment 设置某一个int类型的字段 自动增加
#前提:是数字且 唯一unique
# auto_increment自带not null效果
# 设置条件 int unique
# primary key 设置某一个字段非空且不能重复
# 约束力相当于 not null + unique
# 一张表只能由一个主键
# 联合主键 primary(字段1,字段2)
# foreign key 外键
# references
# 级联删除和更新 on update cas
# 外键关联的那张表的字段必须是unique
# not null
# default
# create table t2(
# id int not null,
# name char(12) not null,
# age int default 18,
# gender enum('male','female') not null default 'male'
# )
# unique 设置某一个字段不能重复
# create table t3(
# id int unique,
# username char(12) unique,
# password char(18)
# );
# 联合唯一
# create table t4(
# id int,
# ip char(15),
# server char(10),
# port int,
# unique(ip,port)
# );
# 自增
# auto_increment 自带not null 效果
# 自增字段 必须是数字 且 必须是唯一的
# create table t5(
# id int unique auto_increment,
# username char(10),
# password char(18)
# )
# insert into t5(username,password) values('alex','alex3714')
# primary key 主键 = not null + unique
# 一张表只能设置一个主键
# 一张表最好设置一个主键
# 约束这个字段 非空(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
# )
# 联合主键
# create table t4(
# id int,
# ip char(15),
# server char(10),
# port int,
# primary key(ip,port)
# );
# 外键 foreign key 涉及到两张表
# 员工表
# create table staff(
# id int primary key auto_increment,
# age int,
# gender enum('male','female'),
# salary float(8,2),
# hire_date date,
# post_id int,
# foreign key(post_id) references post(pid)
# )
# 部门表
# pid postname post_comment post_phone
# create table post(
# pid int primary key,
# postname char(10) not null unique,
# comment varchar(255),
# phone_num char(11)
# )
# update post set pid=2 where pid = 1;
# delete from post where pid = 1;
# 级联删除和级联更新
# create table staff2(
# id int primary key auto_increment,
# 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 set null
# )
4.修改表
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 创建项目之前
# 项目开发、运行过程中
# alter table 表名 add 添加字段
# alter table 表名 drop 删除字段
# alter table 表名 modify 旧字段名字 的类型 宽度 约束
# alter table 表名 change 旧字段名字 新段名字 的类型 宽度 约束
# alter table 表名 add 字段名 数据类型(宽度) 约束 first/after name
# alter table 表名 drop 字段名
# alter table 表名 modify name varchar(12) not null
# alter table 表名 change name new_name varchar(12) not null
# id name age
# alter table 表名 modify age int not null after id;
# alter table 表名 modify age int not null first;
# 删除表
# drop table 表名
5.表关系
# -*- coding:utf-8 -*-
# 两张表中的数据之间的关系
# 多对一 foreign key 永远是在多的那张表中设置外键
# 多个学生都是同一个班级的
# 学生表 关联 班级表
# 学生是多 班级是一
# 一对一 foreign key +unique
# 后出现的后一张表中的数据 作为外键,并且要约束这个外键是唯一的
【被关联的和关联的都要约束unique】
# 客户关系表 : 手机号码 招生老师 上次联系的时间 备注信息
# 学生表 :姓名 入学日期 缴费日期 结业
# 多对多 产生第三张表,把两个关联关系的字段作为第三张表的外键
# 书
# 作者
# 出版社
# 书
6.数据修改
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 增加 insert
# 删除 delete
# 修改 update
# 查询 select
# 增加 insert
# insert into 表名 values (值....)
# 所有的在这个表中的字段都需要按照顺序被填写在这里
# insert into 表名(字段名,字段名。。。) values (值....)
# 所有在字段位置填写了名字的字段和后面的值必须是一一对应
# insert into 表名(字段名,字段名。。。) values (值....),(值....),(值....)
# 所有在字段位置填写了名字的字段和后面的值必须是一一对应
# value单数 values复数
# 一次性写入一行数据 一次性写入多行数据
# t1 id,name,age
# insert into t1 value (1,'alex',83)
# insert into t1 values (1,'alex',83),(2,'wusir',74)
# insert into t1(name,age) value ('alex',83)
# insert into t1(name,age) values ('alex',83),('wusir',74)
# 第一个角度
# 写入一行内容还是写入多行
# insert into 表名 values (值....)
# insert into 表名 values (值....),(值....),(值....)
# 第二个角度
# 是把这一行所有的内容都写入
# insert into 表名 values (值....)
# 指定字段写入
# insert into 表名(字段1,字段2) values (值1,值2)
# 删除 delete
# delete from 表 where 条件;
# 更新 update
# update 表 set 字段=新的值 where 条件;
# 查询
# select语句
# select * from 表
# select 字段,字段.. from 表
# select distinct 字段,字段.. from 表 # 按照查出来的字段去重
# select 字段*5 from 表 # 按照查出来的字段去重
# select 字段 as 新名字,字段 as 新名字 from 表 # 按照查出来的字段去重
# select 字段 新名字 from 表 # 按照查出来的字段去重
7.作业
# 1.默写
# 创建库
# create database day39
# 查看有哪些库
# show databases;
# 查看当前所在的数据库
# select database();
# 切换库
# use 库名
# 2.建表
# 把表与表之间的关系 约束 都加上 再完成博客上的建表联系
# 3.修改表结构的sql语句敲一遍
# 4.select语句后面的练习题
# 1 查出所有员工的名字,薪资,格式为
# <名字:egon> <薪资:3000>
# 2 查出所有的岗位(去掉重复)
# 3 查出所有员工名字,以及他们的年薪,年薪的字段名为annual_year
====================================================================
答案
4-1. select concat('名字:',emp_name,'薪资:',salary) from employee;
4-2.select distinct post from employee;
4-3.select concat('名字:',emp_name,'annual_year:',salary*12) from employee;
一张表关联2个外键
create table score(sid int primary key auto_increment,student_id int ,course_id int,number int
,foreign key(student_id) references student(sid))
,foreign key(course_id) references course(cid));
多对多例子
=====================多对多=====================
#'多对多:一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多'
关联
create table book(
id int primary key auto_increment,
name varchar(20),
press_id int not null);
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)
);
#插入四个作者,id依次排开
insert into author(name) values('egon'),('alex'),('yuanhao'),('wpq');
==========第三张表=========做关联---------
create table author2book(
id int not null unique auto_increment,
author_id int not null,
book_id int not null,
foreign key(author_id) references author(id)
on delete cascade on update cascade,
foreign key(book_id) references book(id)
on delete cascade on update cascade,
primary key(author_id,book_id)
);
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);
#每个作者与自己的代表作如下
egon:
九阳神功
九阴真经
九阴白骨爪
独孤九剑
降龙十巴掌
葵花宝典
alex:
九阳神功
葵花宝典
yuanhao:
独孤九剑
降龙十巴掌
葵花宝典
wpq:
九阳神功
========================显示结果
mysql> select * from author2book;
+----+-----------+---------+
| id | author_id | book_id |
+----+-----------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
| 5 | 1 | 5 |
| 6 | 1 | 6 |
| 7 | 2 | 1 |
| 8 | 2 | 6 |
| 9 | 3 | 4 |
| 10 | 3 | 5 |
| 11 | 3 | 6 |
| 12 | 4 | 1 |
+----+-----------+---------+
day40 单表查询、多表查询
【重点】分组、聚合、pymysql、单表查询(顺序)、多表查询
1.内容回顾
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 约束
# unsigned 整数类型
# not null 非空(严格模式会影响非空设置的效果)
# default 设置默认值
# unique 唯一
# 联合唯一 unique(字段1,字段2)
# auto_increment 自增
# 前提:必须是数字 且唯一
# 自带:非空 自增效果
# primary key 主键
# 一张表只能由一个主键,并且最好有一个主键
# 约束作用:非空且唯一
# 联合主键:
# primary key(字段1,字段2)
# foreign key 外键
# foreign key(本表字段-外键名) references 外表名(外表字段);
# 外键关联的那张表中的字段必须 unique
# 级联操作:on update cascade on delete cascade
# 表与表之间的关系
# 多对一
# foreign key(多) references 表(一)
# 多个学生对应一个班级
# 多个员工对应一个部门
# 多本书对应一个作者
# 多个商品对应一个店铺、订单
# 一对一
# 后一 类型 unique
# foreign key(后一) references 表(先一)
# 一个客户对应一个学生 学生表有外键
# 一个商品 有一个商品详情 详情页中有外键
# 多对多
# 第三张表
# foreign key(外键名1) references 表1(主键)
# foreign key(外键名2) references 表2(主键)
# 多个学生对应一个班级,多个班级对应一个学生
# 多个员工对应一个部门,多个部门对应一个员工
# 多本书对应一个作者,多个作者对应一本书
# 多个商品对应一个店铺、订单,多个店铺对应一个商品
# 一个学生学习多门课程,一门课程被多个学上学习
# 数据的操作
# 增
# insert into 表 values (一条数据),(另一条数据);
# insert into 表(字段1,字段2) values (值1,值2),(值1,值2);
# 删
# delete from 表 where 条件;
# 改
# update 表 set 字段=值 where 条件
# 查
# 单表查
# select语句
# select * from 表
# select 字段 from 表
# select 字段,字段2 from 表
# select 字段 as 新名字 from 表
# select 字段 新名字 from 表
# select distince 字段 from 表; 去重
# select 字段 *10 from 表
2.默写讲解
# book :id name price author_id
# author:aid name birthday gender
# 作者与书 一对多
# create table author(
# aid primary key auto_increment,
# name char(12) not null,
# birthday date,
# gender enum('male','female') default 'male'
# )
# create table book(
# id int primary key,
# name char(12) not null,
# price float(5,2)
# author_id int,
# foreign key(author_id) references author(aid)
# )
# 作者与书一对一
# create table author(
# aid primary key auto_increment,
# name char(12) not null,
# birthday date,
# gender enum('male','female') default 'male'
# )
# create table book(
# id int primary key,
# name char(12) not null,
# price float(5,2)
# author_id int unique,
# foreign key(author_id) references author(aid)
# )
# 作者与书多对多
# create table author(
# aid primary key auto_increment,
# name char(12) not null,
# birthday date,
# gender enum('male','female') default 'male'
# )
# create table book(
# id int primary key,
# name char(12) not null,
# price float(5,2)
# )
# create table book_author(
# id int primary key auto_increment,
# book_id int not null,
# author_id int not null,
# foreign key(book_id) references book(id),
# foreign key(author_id) references author(aid),
# );
3.where 语句
where字句中可以使用:
\1. 比较运算符:> < >= <= <> !=
\2. between 80 and 100 值在80到100之间
\3. in(80,90,100) 值是80或90或100 not in
\4. like 'e%'
通配符可以是%或_,
%表示任意多字符
_表示一个字符
\5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
\6.对于值是null where 条件 is null ,is not null;
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 比较运算 > < = >= <= != <>
# 范围筛选
# 多选一 字段名 in (值1,值2,值3)
# 20000,30000,3000,19000,18000,17000
# select * from employee where salary in (20000,30000,3000,19000,18000,17000)
# 在一个模糊的范围里 between 10000 and 20000
# 在一个数值区间 1w-2w之间的所有人的名字
# select emp_name from employee where salary between 10000 and 20000;
# 字符串的模糊查询 like
# 通配符 % 匹配任意长度的任意内容
# 通配符 _ 匹配一个字符长度的任意内容
# 正则匹配 regexp 更加细粒度的匹配的时候
# select * from 表 where 字段 regexp 正则表达式
# select * from employee where emp_name regexp '^j[a-z]{5}'
# 逻辑运算 - 条件的拼接
# 与 and
# 或 or
# 非 not
# select * from employee where salary not in (20000,30000,3000,19000,18000,17000)
# 身份运算 - 关于null is null /is not null
# 查看岗位描述不为NULL的员工信息
# select * from employee where post_comment is not null;
# 查看岗位是teacher且名字是jin开头的员工姓名、年薪
#select emp_name,salary*12 from employee where post='teacher' and emp_name like 'jin%'
#select emp_name,salary*12 from employee where post='teacher' and emp_name regexp '^jin.*'
4.分组、聚合
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 分组 group by
# select * from employee group by post
# 会把在group by后面的这个字段,也就是post字段中的每一个不同的项都保留下来
# 并且把值是这一项的的所有行归为一组
# 聚合【聚合函数】 把很多行的同一个字段进行一些统计,最终的到一个结果
# count(字段) 统计这个字段有多少项
# sum(字段) 统计这个字段对应的数值的和
# avg(字段) 统计这个字段对应的数值的平均值
# min(字段)
# max(字段)
# 分组聚合
# 求各个部门的人数
# select count(*) from employee group by post
# 求公司里 男生 和女生的人数
# select count(id) from employee group by sex
# 求各部门的平均薪资
# 求各部门的平均年龄
# 求各部门年龄最小的
# select post,min(age) from employee group by post
# 求各部门年龄最大的
# 求各部门薪资最高的
# 求各部门薪资最低的
# 求最晚入职的
# 求最早入职的
# 求各部门最晚入职的
# 求各部门最早入职的
# 求部门的最高薪资或者求公司的最高薪资都可以通过聚合函数取到
# 但是要得到对应的人,就必须通过多表查询
# 总是根据会重复的项来进行分组
# 分组总是和聚合函数一起用 最大 最小 平均 求和 有多少项
5.having、orderby、limit
#!!!执行优先级从高到低:where > group by > having
#1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。
#2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# having 条件 # 过滤 组
# 部门人数大于3的部门
# select post from employee group by post having count(*) > 3
# 1.执行顺序 总是先执行where 再执行group by分组
# 所以相关先分组 之后再根据分组做某些条件筛选的时候 where都用不上
# 2.只能用having来完成
# 平均薪资大于10000的部门
# select post from employee group by post having avg(salary) > 10000
# select * from employee having age>18
# order by
# order by 某一个字段 asc; 默认是升序asc 从小到大
# order by 某一个字段 desc; 指定降序排列desc 从大到小
# order by 第一个字段 asc,第二个字段 desc;
# 指定先根据第一个字段升序排列,在第一个字段相同的情况下,再根据第二个字段排列
# limit
# 取前n个 limit n == limit 0,n
# 考试成绩的前三名
# 入职时间最晚的前三个
# 分页 limit m,n 从m+1开始取n个
# 员工展示的网页
# 18个员工
# 每一页展示5个员工
# limit n offset m == limit m,n 从m+1开始取n个
6.单表查询顺序
# select distinct 需要显示的列 from 表 |
# where 条件 |
# group by 分组 |
# having 过滤组条件 |
# order by 排序
# limit 前n 条
1.找到表:from
2.拿着where指定的约束条件,去文件/表中取出一条条记录
3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4.执行select(去重)
5.将分组的结果进行having过滤
6.将结果按条件排序:order by
7.限制结果的显示条数 limit
7.pymysql模块
============================== 基本用法 =================================
import pymysql
# conn = pymysql.connect(host='127.0.0.1', user='root', password="123",
# database='day40')
# cur = conn.cursor() # 数据库操作符 游标
# # cur.execute('insert into employee(emp_name,sex,age,hire_date) '
# # 'values ("郭凯丰","male",40,20190808)')
# # cur.execute('delete from employee where id = 18')
# conn.commit()
# conn.close()
============================== 基本用法 =================================
# conn = pymysql.connect(host='127.0.0.1', user='root', password="123",
# database='day40')
# cur = conn.cursor(pymysql.cursors.DictCursor) # 数据库操作符 游标
# cur.execute('select * from employee '
# 'where id > 10')
# ret = cur.fetchone()
# print(ret['emp_name'])
# # ret = cur.fetchmany(5)
# ret = cur.fetchall()
# print(ret)
# conn.close()
# select * from employee where id > 10
# sql注入风险
8.多表查询
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 多表查询
# 两张表是怎么连在一起的
# select * from emp,department; # 交叉连接:不适用任何匹配条件。生成笛卡尔积
# 连表查询
# 把两张表连在一起查
# 内链接 inner join 两张表条件不匹配的项不会出现再结果中
# select * from emp inner join department on emp.dep_id = department.id;
# 外连接
# 左外连接 left join 永远显示全量的左表中的数据 ,没有就为null
# 本质就是:在内连接的基础上增加左边有右边没有的结果
# select * from emp left join department on emp.dep_id = department.id;
# 右外连接 right join 永远显示全量的右表中的数据,没有就为null
# select * from emp right join department on emp.dep_id = department.id;
# 全外连接
全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果
# select * from emp left join department on emp.dep_id = department.id
# union
# select * from department right join emp on emp.dep_id = department.id;
9.子查询
# 子查询
# 找技术部门的所有人的姓名
# 先找到部门表技术部门的部门id
# select id from department where name = '技术';
# 再找emp表中部门id = 200
# select name from emp where dep_id = (select id from department where name = '技术');
# 找到技术部门和销售部门所有人的姓名
# 先找到技术部门和销售部门的的部门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.dep_id = department.id where department.name in ('技术','销售');
# 连接的语法
# select 字段 from 表1 xxx join 表2 on 表1.字段 = 表2.字段;
# 常用
# 内链接
# 左外链接
# 找技术部门的所有人的姓名
# select * from emp inner join department on emp.dep_id = department.id;
# +----+-----------+--------+------+--------+------+--------------+
# | id | name | sex | age | dep_id | id | name |
# +----+-----------+--------+------+--------+------+--------------+
# | 1 | egon | male | 18 | 200 | 200 | 技术 |
# | 2 | alex | female | 48 | 201 | 201 | 人力资源 |
# | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 |
# | 4 | yuanhao | female | 28 | 202 | 202 | 销售 |
# | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 |
# +----+-----------+--------+------+--------+------+--------------+
# select * from emp inner join department on emp.dep_id = department.id where department.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的升序顺序来连表查询emp和department
# select * from emp inner join department as d on emp.dep_id = d.id order by age;
# 优先使用连表查询,因为连表查询的效率高
# 练习
# 查询平均年龄在25岁以上的部门名
# 部门名 department表
# select name from department where id in (
# select dep_id from emp group by dep_id having avg(age)>25
# );
# 员工表
# select dep_id,avg(age) from emp group by dep_id;
# select dep_id from emp group by dep_id having avg(age)>25;
# 查看不足1人的部门名(子查询得到的是有人的部门id)
# 查emp表中有哪些部门id
# select dep_id from emp group by dep_id;
# 再看department表中
# select * from department where id not in (???)
# select * from department where id not in (select dep_id from emp group by dep_id);
# 查询大于所有人平均年龄的员工名与年龄
# select * from emp where age>(select avg(age) from emp);
# 查询大于部门内平均年龄的员工名、年龄
# select dep_id,avg(age) from emp group by dep_id;
# select * from emp inner join (select dep_id,avg(age) avg_age from emp group by dep_id) as d
# on emp.dep_id = d.dep_id where emp.age > d.avg_age;
10.day40作业
1.单表查询基础的语法和顺序背下来
2.继续把下午的小练习做完
3.多表查询的连表和子查询的语法的整理
4.课上的所有sql语句敲一遍
5.根据博客上的要求完成 :查询每个部门最新入职的那位员工
select * from employee where hire_date in (select max(hire_date) from employee group by office);
6.记忆一下 pymysql的用法
day41 索引原理、事物
1.内容回顾
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 单表查询
# select (distinct)
# from
# where
# 比较运算符 > < = != <> >= <=
# 逻辑运算符 and or not
# 身份运算符 is is not --> null
# 范围
# 多选一 :in (12,34,6) / in ('技术','销售')
# 数字的范围:between a and b
# 字符串的范围
# like % _
# regexp 正则
# group by 分组
# 聚合函数 count sum avg min max
# having 过滤组
# 在groupby之后执行的
# having中可以使用聚合函数
# having 后面的条件要么是select的字段,要么是分组的字段
# order by
# 排序 asc(默认,从小到大); desc(从大到小)
# limit (offset)
# limit n
# limit m,n == limit n offset m
# 多表查询
# 连表查询 更高效
# 内连接 inner join
# 外连接 left join/rignt join
# 子查询
# 在查询一个结果的时候,依赖一个条件也是一个sql语句
2.习题讲解
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 用户表 user
# create table user(
# uid int primary key auto_increment,
# username char(12)
# )
# 订单表 orders
# create table orders(
# oid int primary key auto_increment,
# otime datetime,
# payment float(10,2),
# uid int,
# foreign key(uid) references user(uid)
# )
# insert into user(username) values ('alex'),('太白');
# insert into orders(otime,payment,uid) values (20190524093800,1320,1),(20180524093800,2000,2);
# 查订单表,按照支付时间从早到晚排序
# 从小到大
# select * from orders order by otime;
# 查询每个用户购买的订单数
# select uid,count(*) from orders group by uid; uid和订单数
# select * from user inner join (select uid,count(*) from orders group by uid) as o on user.uid = o.uid;
# select username,count_order from user inner join (select uid,count(*) as count_order from orders group by uid) as o on user.uid = o.uid;
# 查购买的订单总额最高的用户名
# 查购买的订单总额最高的uid
# select uid,sum(payment) from orders group by uid;
# select uid,sum(payment) as sum_pay from orders group by uid order by sum_pay desc;
# select uid,sum(payment) as sum_pay from orders group by uid order by sum_pay desc limit 1;
# select username from user inner join (select uid,sum(payment) as sum_pay from orders group by uid order by sum_pay desc limit 1) pay on user.uid = pay.uid;
# 删除订单编号为3的订单信息
# delete from orders where oid = 2;
# 订单4的支付金额修改成400
# update orders set payment=400 where oid=4;
3.今日内容
# 索引原理
# 正确的使用索引
# 数据库的备份,表的备份
# 事务和锁
# sql注入和pymsql
4.索引原理
数据库的存储方式
索引的种类
聚集索引和辅助索引
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 什么是索引 -- 目录
# 就是建立起的一个在存储表阶段
# 就有的一个存储结构能在查询的时候加速
# 索引的重要性
# 读写比例 : 10:1
# 读(查询)的速度就至关重要了
# 索引的原理
# block 磁盘预读原理
# for line in f
# 4096个字节
# 读硬盘的io操作的时间非常的长,比CPU执行指令的时间长很多
# 尽量的减少IO次数才是读写数据的主要要解决的问题
# 数据库的存储方式
# 新的数据结构 —— 树
# 平衡树 balance tree - b树
# 在b树的基础上进行了改良 - b+树
# 1.分支节点和根节点都不再存储实际的数据了
# 让分支和根节点能存储更多的索引的信息
# 就降低了树的高度
# 所有的实际数据都存储在叶子节点中
# 2.在叶子节点之间加入了双向的链式结构
# 方便在查询中的范围条件
# mysql当中所有的b+树索引的高度都基本控制在3层
# 1.io操作的次数非常稳定 【通过索引,io基本稳定在三次左右,就能查到了,回表也就5次】
# 2.有利于通过范围查询
# 什么会影响索引的效率 —— 树的高度
# 1.对哪一列创建索引,选择尽量短的列做索引
# 2.对区分度高的列建索引,重复率超过了10%那么不适合创建索引
# 聚集索引和辅助索引
# 在innodb中 聚集索引和辅助索引并存的
# 聚集索引 - 主键 更快
# 数据直接存储在树结构的叶子节点
# 辅助索引 - 除了主键之外所有的索引都是辅助索引 稍慢
# 数据不直接存储在树中
# 在myisam中 只有辅助索引,没有聚集索引
# 索引的种类
# primary key 主键 聚集索引 约束的作用:非空 + 唯一
# 联合主键
# unique 自带索引 辅助索引 约束的作用:唯一
# 联合唯一
# index 辅助索引 没有约束作用
# 联合索引
# 看一下如何创建索引、创建索引之后的变化
# create index 索引名字 on 表(字段)
# DROP INDEX 索引名 ON 表名字;
# 索引是如何发挥作用的
# select * from 表 where id = xxxxx
# 在id字段没有索引的时候,效率低
# 在id字段有索引的之后,效率高
5.正确使用索引
索引不生效的原因?
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 以email为条件查询
# 不添加索引的时候肯定慢
# 查询的字段不是索引字段,也慢
# id作为条件的时候
# 如果不加索引,速度慢
# 加了索引,速度快
'索引不生效的原因?
# 要查询的数据的范围大
# > < >= <= !=
# between and
# select * from 表 order by age limit 0,5
# select * from 表 where id between 1000000 and 1000005;
# like
# 结果的范围大 索引不生效
# 如果 abc% 索引生效,%abc索引就不生效
# 如果一列内容的区分度不高,索引也不生效
# name列
# 索引列不能在条件中参与计算
# select * from s1 where id*10 = 1000000; 索引不生效
# 对两列内容进行条件查询
# and and条件两端的内容,优先选择一个有索引的,并且树形结构更好的,来进行查询
# 两个条件都成立才能完成where条件,先完成范围小的缩小后面条件的压力
# select * from s1 where id =1000000 and email = 'eva1000000@oldboy';
# or or条件的,不会进行优化,只是根据条件从左到右依次筛选
# 条件中带有or的要想命中索引,这些条件中所有的列都是索引列
# select * from s1 where id =1000000 or email = 'eva1000000@oldboy';
# 联合索引 # create index ind_mix on s1(id,name,email);
# select * from s1 where id =1000000 and email = 'eva1000000@oldboy';
# 在联合索引中如果使用了or条件索引就不能生效
# select * from s1 where id =1000000 or email = 'eva1000000@oldboy';
# 最左前缀原则 :在联合索引中,条件必须含有在创建索引的时候的第一个索引列
# select * from s1 where id =1000000; 能命中索引
# select * from s1 where email = 'eva1000000@oldboy'; 不能命中索引
# (a,b,c,d)
# a,b
# a,c
# a
# a,d
# a,b,d
# a,c,d
# a,b,c,d
# 在整个条件中,从开始出现模糊匹配的那一刻,索引就失效了
# select * from s1 where id >1000000 and email = 'eva1000001@oldboy';
# select * from s1 where id =1000000 and email like 'eva%';
# 什么时候用联合索引
# 只对 a 对abc 条件进行索引
# 而不会对b,对c进行单列的索引
# 单列索引
# 选择一个区分度高的列建立索引,条件中的列不要参与计算,条件的范围尽量小,使用and作为条件的连接符
# 使用or来连接多个条件
# 在满上上述条件的基础上
# 对or相关的所有列分别创建索引
# 覆盖索引
# 如果我们使用索引作为条件查询,查询完毕之后,不需要回表查,覆盖索引
# explain select id from s1 where id = 1000000;
# explain select count(id) from s1 where id > 1000000;
# 合并索引
# 对两个字段分别创建索引,由于sql的条件让两个索引同时生效了,那么这个时候这两个索引就成为了合并索引
# 执行计划 : 如果你想在执行sql之前就知道sql语句的执行情况,那么可以使用执行计划
# 情况1:
# 30000000条数据
# sql 20s
# explain sql --> 并不会真正的执行sql,而是会给你列出一个执行计划
# 情况2:
# 20条数据 --> 30000000
# explain sql
# 原理和概念
# b树
# b+树
# 聚集索引 - innodb
# 辅助索引 - innodb myisam
# SQL索引的创建(单个、联合)、删除
# 索引的命中:范围,条件的字段是否参与计算(不能用函数),列的区分度(长度),条件and/or,联合索引的最左前缀问题
# 一些名词
# 覆盖索引
# 合并索引
# explain执行计划
# 建表、使用sql语句的时候注意的
# char 代替 varchar
# 连表 代替 子查询
# 创建表的时候 固定长度的字段放在前面
6.数据备份与事物
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# mysqldump -uroot -p123 day40 > D:\code\s21day41\day40.sql
# mysqldump -uroot -p123 --databases new_db > D:\code\s21day41\db.sql
# begin; # 开启事务
# select * from emp where id = 1 for update; # 查询id值,for update添加行锁;
# update emp set salary=10000 where id = 1; # 完成更新
# commit; # 提交事务
7.sql注入
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# create table userinfo(
# id int primary key auto_increment,
# name char(12) unique not null,
# password char(18) not null
# )
#
# insert into userinfo(name,password) values('alex','alex3714')
# 输入用户
# 输入密码
#
# 用户名和密码到数据库里查询数据
# 如果能查到数据 说明用户名和密码正确
# 如果查不到,说明用户名和密码不对
# username = input('user >>>')
# password = input('passwd >>>')
# sql = "select * from userinfo where name = '%s' and password = '%s'"%(username,password)
# print(sql)
# -- 注释掉--之后的sql语句
# select * from userinfo where name = 'alex' ;-- and password = '792164987034';
# select * from userinfo where name = 219879 or 1=1 ;-- and password = 792164987034;
# select * from userinfo where name = '219879' or 1=1 ;-- and password = '792164987034';
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))
print(cur.fetchone())
cur.close()
conn.close()
8.作业
作业 https://www.cnblogs.com/Eva-J/articles/9688383.html
1.初级需求
1、查询男生、女生的人数;
select gender,count(gender) from student group by gender;
2、查询姓“张”的学生名单;
select sname from student where sname like'张%';
3、课程平均分从高到低显示
select avg(num) from score group by course_id order by avg(num) desc;
4、查询有课程成绩小于60分的同学的学号、姓名;
select sid,sname from student where sid in (select sid from score where num<60);
5、查询至少有一门课与学号为1的同学所学课程相同的同学的学号和姓名;
select sid,sname from student where sid in (select student_id from score where course_id in (select course_id from score where student_id=1));
6、查询出只选修了一门课程的全部学生的学号和姓名;
select sid,sname from student where sid in (select student_id from score group by student_id having count(course_id)=1);
7、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;
select course_id,max(num),min(num) from score where num group by course_id;
8、查询课程编号“2”的成绩比课程编号“1”课程低的所有同学的学号、姓名;
9、查询“生物”课程比“物理”课程成绩高的所有学生的学号;
10、查询平均成绩大于60分的同学的学号和平均成绩;
11、查询所有同学的学号、姓名、选课数、总成绩;
12、查询姓“李”的老师的个数;
13、查询没学过“张磊老师”课的同学的学号、姓名;
14、查询学过“1”并且也学过编号“2”课程的同学的学号、姓名;
15、查询学过“李平老师”所教的所有课的同学的学号、姓名;
2.高级需求
1、查询没有学全所有课的同学的学号、姓名;
2、查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名;
3、删除学习“叶平”老师课的SC表记录;
4、向SC表中插入一些记录,这些记录要求符合以下条件:①没有上过编号“002”课程的同学学号;②插入“002”号课程的平均成绩;
5、按平均成绩从低到高显示所有学生的“语文”、“数学”、“英语”三门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,有效课程数,有效平均分;
6、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;
7、按各科平均成绩从低到高和及格率的百分数从高到低顺序;
8、查询各科成绩前三名的记录:(不考虑成绩并列情况)
9、查询每门课程被选修的学生数;
10、查询同名同姓学生名单,并统计同名人数;
11、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列;
12、查询平均成绩大于85的所有学生的学号、姓名和平均成绩;
13、查询课程名称为“数学”,且分数低于60的学生姓名和分数;
14、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名;
15、求选了课程的学生人数
16、查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩;
17、查询各个课程及相应的选修人数;
18、查询不同课程但成绩相同的学生的学号、课程号、学生成绩;
19、查询每门课程成绩最好的前两名;
20、检索至少选修两门课程的学生学号;
21、查询全部学生都选修的课程的课程号和课程名;
22、查询没学过“叶平”老师讲授的任一门课程的学生姓名;
23、查询两门以上不及格课程的同学的学号及其平均成绩;
24、检索“004”课程分数小于60,按分数降序排列的同学学号;
25、删除“002”同学的“001”课程的成绩;