6、多表操作
有两张表想要一起查询
select * from dep,emp; # 结果 笛卡尔积,不可用
拼表操作 对应的方法
inner join 内连接
left join 左连接
right join 右连接
union 全连接
# inner join 内连接
select * from emp inner join dep on emp.dep_id = dep.id;
# 只拼接两张表中公有的数据部分
# left join 左连接
select * from emp left join dep on emp.dep_id = dep.id;
# 左表所有的数据都展示出来 没有对应的项就用NULL
# right join 右连接
select * from emp right join dep on emp.dep_id = dep.id;
# 右表所有的数据都展示出来 没有对应的项就用NULL
# union 全连接 左右两表所有的数据都展示出来
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;
6.1子查询
分步骤解决问题
# 将一个查询语句的结果当做另外一个查询语句的条件去用
# 查询部门是技术或者人力资源的员工信息
1 先获取部门的id号
2 再去员工表里面筛选出对应的员工
select id from dep where name='技术' or name = '人力资源';
select name from emp where dep_id in (200,201);
select * from emp where dep_id in (select id from dep where name='技术' or name = '人力资源');
表的查询结果可以作为其他表的查询条件
也可以通过起别名的方式把它作为一个张虚拟表根其他表关联
多表查询的方式:
1.拼表,在查询
2.子查询
关键字exists(了解)
只返回布尔值 True False
返回True的时候外层查询语句执行
返回False的时候外层查询语句不再执行
select * from emp where exists
(select id from dep where id>3);
select * from emp where exists
(select id from dep where id>300);
7、pymysql
pymysql是支持Python代码操作数据库MySQL的模块
安装:
pip3 install pymysql
语句
import pymysql
# 链接数据库
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'root',
password= '123456',
database='mydb',
charset='utf8' # 编码不要加-
)
# 生成一个游标对象,用来执行命令的
# cursor = conn.cursor() # 返回的结果是元组
# 将查询结果以字典的形式返回
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from teacher;'
res = cursor.execute(sql)
# print(res) # 4 返回的是当前sql语句所影响的行数 该返回值一般不用
# print(cursor.fetchone()) # 只拿一条结果
print(cursor.fetchall()) # 拿所有的结果
print(cursor.fetchmany(2)) # 可以指定拿几条
# 读取数据相当于光标的移动
print(cursor.fetchone()) # 拿第一条
print(cursor.fetchone()) # 拿第二条
print(cursor.fetchone()) # 拿第三条
# 相对移动
cursor.scroll(1,'relative') # 相当于光标所在的位置继续向后移动一位
print(cursor.fetchall())
# 绝对移动
cursor.scroll(1,'absolute') # 相当于光标所在的起始位置往后移动一位
print(cursor.fetchone())
用户名登录与数据库
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='mydb',
charset='utf8',
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
username = input('>>>:').strip()
password = input('>>>:')
# 不要手动拼接数据,将需要拼接的数据用execute方法即可
sql = "select * from user where name=%s and password=%s"
rows = cursor.execute(sql,(username,password))
if rows:
print('登录成功')
else:
print('用户名和密码错误')
# 增删改查中,删改增它们的操作设计到数据的修改 需要二次确认
import pymysql
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'root',
passwd = '123456',
db = 'day48',
charset = 'utf8',
autocommit = True # 如果不想写conn.commit() ,可以添加这行代码
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 增
sql = 'insert into user(name,password) values(%s,%s)'
# rows = cursor.execute(sql,('haha',123))
# 可以一次添加多个
rows = cursor.executemany(sql,[('xxx',123),('ooo',123),('yyy',123)])
print(rows)
# conn.commit() # 确认
# 修改
# sql = 'update user set name="jasonNB" where id=1'
# rows = cursor.execute(sql)
# print(rows)
# conn.commit() # 确认
# 删除
sql = 'delete from user where id=7'
rows = cursor.execute(sql)
print(rows)
conn.commit() # 确认
# 查
# sql = 'select * from user'
# cursor.execute(sql)
# print(cursor.fetchall())
8、视图(了解)
1、什么是视图
试图就是通过sql查询得到一张虚拟表,然后保存下来,下次可以直接使用
2、为什么要用视图
如果要频繁的操作一张虚拟表,就可以制作视图,然后后续直接使用
3、如何使用视图
语法
create view 表名 as 需要创建sql语句
create view teacher2course as
select * from teacher INNER JOIN course
on teacher.tid = course.teacher_id
;
注意:
1、创建视图在硬盘上只会有表结构,数据还是来自于之前的表
2、不要对视图的表进行修改,会影响原来的表的数据
3、视图使用的频率一般不高
9、触发器(了解)
满足对表数据增删改的情况下,自动触发的功能
使用触发器可以帮助我们实现监控、日志…
触发器可以在六种情况下自动触发 增前 增后 删前删后 改前改后
create trigger 触发器的名字 before/after insert/update/delete on 表名
for each row
begin
sql语句
end
# 具体使用 针对触发器的名字 我们通常需要做到见名知意
# 针对增
create trigger tri_before_insert_t1 before insert on t1
for each row
begin
sql语句
end
create trigger tri_after_insert_t1 after insert on t1
for each row
begin
sql语句
end
修改MySQL的默认结束符
# 修改MySQL默认的语句结束符 只作用于当前窗口
delimiter $$ # 将默认的结束符号由;改为$$
delimiter ;
修改默认结束符的作用
-- 当cmd表中的记录succes字段是no那么就触发触发器的执行去errlog表中插入数据--
# NEW指代的就是一条条数据对象
CREATE TABLE cmd (
id INT PRIMARY KEY auto_increment,
USER CHAR (32),
priv CHAR (10),
cmd CHAR (64),
sub_time datetime, #提交时间
success enum ('yes', 'no') #0代表执行失败
);
CREATE TABLE errlog (
id INT PRIMARY KEY auto_increment,
err_cmd CHAR (64),
err_time datetime
);
delimiter $$
create trigger tri_after_insert_cmd after insert on cmd
for each row
begin
if NEW.success = 'no' then
insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
end if;
end $$
delimiter ;
# 朝cmd表插入数据
INSERT INTO cmd (
USER,
priv,
cmd,
sub_time,
success
)
VALUES
('j','0755','ls -l /etc',NOW(),'yes'),
('j','0755','cat /etc/passwd',NOW(),'no'),
('j','0755','useradd xxx',NOW(),'no'),
('j','0755','ps aux',NOW(),'yes');
# 删除触发器
drop trigger tri_after_insert_cmd;
10、事务(了解)
1、什么是事务
开启一个事务可以包含多条sql语句,这些sql语句要么同时成功,
要么一个都别想成功, 称之为事务的原子性。
2、事务的作用
保证了对数据操作的安全性
3.事务的四大特性
ACID
A:原子性
一个事务是一个不可分割的单位,事务中包含的诸多操作
要么同时成功要么同时失败
C:一致性
事务必须是使数据库从一个一致性的状态变到另外一个一致性的状态
一致性跟原子性是密切相关的
I:隔离性
一个事务的执行不能被其他事务干扰
(即一个事务内部的操作及使用到的数据对并发的其他事务是隔离的,并发执行的事务之间也是互相不干扰的)
D:持久性
也叫”永久性”
一个事务一旦提交成功执行成功 那么它对数据库中数据的
4、如何使用事务
# 1、开启事务
start transaction;
# 2、回滚(回到事务执行之前的状态)
rollback;
# 3、二次确认,确认之后就无法回滚了
commit;
# 模拟转账功能
create table user(
id int primary key auto_increment,
name char(16),
balance int
);
insert into user(name,balance) values
('a',1000),
('b',1000),
('c',1000);
# 1 先开启事务
start transaction;
# 2 多条sql语句
update user set balance=900 where name='a';
update user set balance=1010 where name='b';
update user set balance=1090 where name='c';
如果想让多条sql语句保持一致性,同时成功,同时失败,就应该使用事务。
10、存储过程(了解)
存储过程类似于Python中的自定义函数。
存储过程内部包含了一系列可以执行的sql语句,存储过程存放于MySQL服务端中,可以直接通过调用存储过程触发内部sql语句的执行
create procedure 存储过程的名字(形参1,形参2,...)
begin
sql代码
end
# 调用
call 存储过程的名字();
三种开发模式
1、
应用程序由程序员写代码开发
MySQL提前编写好存储过程,供应用程序调用
好处:开发效率提升,执行效率提高
缺点:扩展性差,需要跨部门沟通
2、
应用程序与MySQL都由程序员来写
优点:扩展性高
缺点:开发效率低,编写sql语句太过频繁
3、
应用程序:只写程序代码,不写sql语句,基于别人写好的操作MySQL的Python框架
优点:开发效率提高
缺点:语句的扩展性可能会出现效率低下的问题
第一种方式基本上不用,一般使用第二种和第三种方式。
delimiter $$
create procedure p1(
in m int, # 只进不出 m不能返回出去
in n int,
out res int # 该形参可以返回出去
)
begin
select tname from teacher where tid>m and tid<n;
set res=666; # 将res变量修改 用来标识当前的存储过程代码确实执行了
end $$
delimiter ;
# 针对形参res 不能直接传数据 应该传一个变量名
# 定义变量
set @ret = 10;
# 查看变量对应的值
select @ret;
pymysql中使用存储过程
import pymysql
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'root',
passwd = '123456',
db = 'day48',
charset = 'utf8',
autocommit = True
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 调用存储过程
cursor.callproc('p1',(1,5,10))
"""
@_p1_0=1
@_p1_1=5
@_p1_2=10
"""
# print(cursor.fetchall())
cursor.execute('select @_p1_2;')
print(cursor.fetchall())
11、函数(了解)
跟存储过程是有区别的,存储过程是自定义函数,函数就类似于是内置函数
('jason','0755','ls -l /etc',NOW(),'yes')
CREATE TABLE blog (
id INT PRIMARY KEY auto_increment,
NAME CHAR (32),
sub_time datetime
);
INSERT INTO blog (NAME, sub_time)
VALUES
('第1篇','2015-03-01 11:31:21'),
('第2篇','2015-03-11 16:31:21'),
('第3篇','2016-07-01 10:21:31'),
('第4篇','2016-07-22 09:23:21'),
('第5篇','2016-07-23 10:11:11'),
('第6篇','2016-07-25 11:21:31'),
('第7篇','2017-03-01 15:33:21'),
('第8篇','2017-03-01 17:32:21'),
('第9篇','2017-03-01 18:31:21');
select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
12、流程控制(了解)
if判断
delimiter //
CREATE PROCEDURE proc_if ()
BEGIN
declare i int default 0;
if i = 1 THEN
SELECT 1;
ELSEIF i = 2 THEN
SELECT 2;
ELSE
SELECT 7;
END IF;
END //
delimiter ;
while循环
delimiter //
CREATE PROCEDURE proc_while ()
BEGIN
DECLARE num INT ;
SET num = 0 ;
WHILE num < 10 DO
SELECT
num ;
SET num = num + 1 ;
END WHILE ;
13、索引
数据都是存在硬盘上的,查询数据需要进行IO操作
索引:一种数据结构,类似于书的目录,这就意味着,以后查询数据的时候先找索引,从而降低IO操作
索引在MySQL中叫键,是存储引擎用于快速查找记录的一种数据结构
比如:primary key、unique key、index key
注意foreign key不是用来加速查询用的,不在我们的而研究范围之内
上面的三种key,前面两种除了可以增加查询速度之外各自还具有约束条件,而最后一种index key没有任何的约束条件,只是用来帮助快速查询数据
本质
通过不断的缩小想要的数据范围筛选出最终的结果,同时将随机事件(一页一页的翻)
变成顺序事件(先找目录、找数据)
也就是说有了索引机制,我们可以总是用一种固定的方式查找数据
一张表中可以有多个索引(多个目录)
索引虽然能够帮助你加快查询速度但是也有缺点
1、当表中有大量的数据存在的前提下,创建索引速度会很慢
2、在索引创建完毕之后,对表的查询性能会大幅度提升,但是写的数据会降低
3、索引不要随意的创建
b+树
只有叶子节点存放的是真实的数据 其他节点存放的是虚拟数据 仅仅是用来指路的
树的层级越高查询数据所需要经历的步骤就越多(树有几层查询数据就需要几步)
一个磁盘块存储是有限制的
为什么建议你将id字段作为索引
占得空间少 一个磁盘块能够存储的数据多
那么久降低了树的高度 从而减少查询次数
聚集索引
聚集索引就是主键
Innodb 建表的时候只有两个文件 直接将主键存放在了idb表中
MyIsam 建表的时候三个文件 单独将索引存在一个文件
辅助索引
查询数据的时候不可能一直使用到主键,也有可能会用到name,password等其他字段
那么这个时候是没有办法利用聚集索引。这个时候就可以根据情况给其他字段设置辅助索引(也是一个b+树)
辅助索引,叶子节点存放的是数据对应的主键值,先按照辅助索引拿到数据的主键值,之后还是需要去主键的聚集索引里面查询数据
覆盖索引
在辅助索引的叶子节点就已经拿到了需要的数据
# 给name设置辅助索引
select name from user where name='j';
# 非覆盖索引
select age from user where name='jason';
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/279055.html