MySQL学习(五)

MySQL学习(五)


上周回顾


查询关键字的使用


where筛选


  select * from 表 where 条件;
  # 对数据进行筛选

group by分组


select * from 表 where 条件 group by 字段名;
# 以字段名对筛选过后的数据进行分组,非主键字段名是,*号处的参数要和字段名保持一致

having过滤


select * from 表 where 条件 group by 字段名 having 条件;
# 进行分组后再次对数据进行一个过滤,where善后版

order by排序


select * from 表 order by 需要排序字段数据;  # 默认是升序(从小到大)
select * from 表 order by 需要排序字段数据 asc;  # 关键字asc 可以省略 
select * from 表 order by 需要排序字段数据 desc;  # 降序(从大到小)

distinct去重


select distinct 字段数据 from 表;
# 只能去重完全一样的数据,被封装的数据带上主键之后无法去重

limit分页


select * from 表 limit 条数;
# 限制展示数据的条数
select * from 表 limit 条数,页数;
# 分页效果
select * from 表 order by 字段名 desc limit 1;
# 数据量过大时,需要使用到limit功能控制展示的条数

regexp正则


select * from emp where name regexp '正则表达式';

多表查询


子查询


( SELECT 字段名 FROM 表 WHERE 条件 GROUP BY 字段名 HAVING 条件 )
# 先对一张表进行操作,拿到结果后,使用结果对另外一张表进行操作
SELECT 字段名 FROM 表 WHERE 条件 GROUP BY 字段名 HAVING 条件 ( SELECT 字段名 FROM 表 WHERE 条件 GROUP BY 字段名 HAVING 条件 )

连表操作


将多张表拼接到一起后,直接对达标进行数据操作

内链接 inner join
select * from 表1 inner join 表2 on 表1.外键字段=表2.主键;
# 只会链接两张表都拥有的数据
左链接 left join
select * from 表1 left join 表2 on 表1.外键字段=表2.主键;
# 左表为基准,右表中没有的数据以NULL填充
右链接 ringht join
select * from 表1 right join 表2 on 表1.外键字段=表2.主键;
# 右表为基准,左表中没有的数据以NULL填充
全链接 union
select * from 表1 left join 表2 on 表1.外键字段=表2.主键
union
select * from 表1 RIGHT join 表2 on 表1.外键字段=表2.主键;
# 左右两表数据全部展示 没有对应项则用NULL填充


今日学习内容


python操作MySQL


pymysql模块
下载:pip3 install pymysql
下载完直接导入模块

import pymysql

1.链接服务端
链接对象名 = pymysql.connect(
	host='127.0.01',  # MySQL服务端的IP地址
port=3306,  # MySQL默认PORT地址(端口号)
      user='',  # 用户名
      password='',  # 密码  也可以简写 passwd
      database='',  # 库名称  也可以简写 db
      charset='utf8'  # 字符编码 utf-8会报错
)
2.产生获取命令的游标对象
光标功能名 = 链接对象名.cursor(
	cursor = pymysql.cursors.DictCursor  # 不填写默认返回元组数据,添加参数将数据转换为字典
)
3.编写SQL语句
# SQL语句会被高亮显示,因为pycharm默认是无法识别SQL语句的
sql_1 = 'show tables;' 
sql_2 = 'select * from 表;'
4.执行SQL语句
用变量名接收 = cursor.execute(sql1);
print(affect_rows) 
# 获取SQL语句之后受影响的行数
5.获取结果
res = cursor.fetchall()
print(res)
# fetchall读取所有内容,光标会移动到最后

获取SQL语句执行的结果 跟读取文件内容的read方法几乎一致(光标)
fetchone()  # 读取结果为单个元组
fetchmany()  # 读取结果为多个元组
fetchall()  # 读取完所有内容
cursor.scroll(1, 'relative')  # 相对于当前位置往后移动一个单位
cursor.scroll(1, 'absolute')  # 相对于起始位置往后移动一个单位

SQL注入问题


注入问题主要是因为外部输入了SQL的注释语法或者逻辑运算符,外部输入的数据改变了原本的代码

解决方式:execute方法

cursor.execute(sql, (需要处理的数据1,需要处理的数据2))
批量插入数据:cursor.executemany(sql,[('1',11),('2',222),('3',333)])

二次确认


数据的增删改查的层级并不相等,查不会影响到数据,直接操作即可;而增删改会影响到真实数据需要二次确认

方式1:代码直接编写

链接对象名.commit()  # 二次确认

方式2:配置固定参数

链接对象名 = pymysql.connect(
    autocommit=True  # 自动二次确认
)

修改表SQL语句补充


1.修改表的名字		rename
	alter table 表 rename 重命名;

2.添加字段		add
	alter table 表 add pwd int;  '''默认是尾部追加字段'''
	alter table 表 add tid int after name;  '''指定追加位置'''
  alter table 表 add nid int first;  '''指定头部添加字段'''
  
3.修改字段    change(名字类型都可)/modify(只能改类型不能改名字)
	alter table 表 change 字段名 重命名 tinyint(类型);
  
4.删除字段		drop
	alter table 表 drop 字段名;

视图


概念:通过sql语句临时获得的一张虚拟表,保存下来之后就被称为'视图'

作用:如果频繁使用一张虚拟表,那么我们可以将他保存下来变成视图,降低操作量

视图的制作:
	create view 视图名 as sql语句

注意事项:保存的视图会占据在库中的表格里,也会占用资源;视图如果过多会造成库下的表混乱;而且库不支持增删改。


触发器


概念:在对表数据进行增、删、改、的该表数据的操作的时候,就会自动触发的功能

作用:为表操作功能进行扩展,增添定制的功能

种类:表数据新增之前、新增之后;表数据修改之前、修改之后;表数据删除之前、删除之后

触发器创建:

create trigger 触发器名字 before/after insert/update/delete
	on 表名 for each row
		begin
			SQL语句
		end	

触发器名字建议:

tri_after_insert_表
tri_before_update_表
tri_before_delete_表

补充:临时修改SQL语句的结束符:delimiter $$

临时修改的原因是因为触发器 存储过程等技术点 代码中也需要使用分号如果不修改 则无法书写出完成的代码


实际案例

1.先创建两张表

    CREATE TABLE cmd (
        id INT PRIMARY KEY auto_increment,  # 主键int类型,自增特性
        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,  # 主键int类型,自增特性
        err_cmd CHAR (64),  # 创建字段名
        err_time datetime  # 获取时间
    );
     2.需求:cmd表插入数据的success如果值为no 则去errlog表中插入一条记录
    delimiter $$  # 将mysql默认的结束符由;换成$$
    create trigger tri_after_insert_cmd after insert on cmd for each row
    begin
        if NEW.success = 'no' then  # 新记录都会被MySQL封装成NEW对象
            insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
        end if;
    end $$
    delimiter ;  # 结束之后记得再改回来,不然后面结束符就都是$$了
  3.仅仅往cmd表中插入数据
  	INSERT INTO cmd (
          USER,
          priv,
          cmd,
          sub_time,
          success
    )VALUES
  4.触发器其他补充
  	查看当前库下所有的触发器信息
    	show triggers\G;
    删除当前库下指定的触发器信息
    	drop trigger 触发器名称;

事物


概念:事物包含诸多SQL语句,并且这些SQL语句;只存在都成功和都失败两种情况

作用:现实生活中,比如说转账,就应该将扣款,和入账做一个事物关联,因为二者一成功则二者成,一失败则皆失败。

四大特性:ACID

A:原子性:一个事务是一个不可分割的整体 里面的操作要么都成立要么都不成立

C:一致性:事务必须使数据库从一个一致性状态变道另一个一致性状态

I:隔离性:并发编程中 多个事务之间是相互隔离的 不会彼此干扰

D:持久性:事物一旦提交,产生的结果应该是永久的

具体使用:

1.创建表及录入数据
  	create table user(
      id int primary key auto_increment,
      name char(32),
      balance int
      );
    insert into user(name,balance)
      values
      ('jason',1000),
      ('eason',100000000000);
   
2.事务操作
开启一个事务的操作
    	start transaction;
    编写SQL语句(同属于一个事务)
    	update user set balance=100000001000 where name='jason';
			update user set balance=0 where name='eason'; 
    事务回滚(返回执行事务操作之前的数据库状态)
    	rollback;  # 执行完回滚之后 事务自动结束
    事务确认(执行完事务的主动操作之后 确认无误之后 需要执行确认命令)
    	commit;  # 执行完确认提交之后 无法回滚 事务自动结束

存储过程


类似python中的自定义函数,一组为了完成特定功能的 SQL 语句集 , 存储在数据库中 , 经过第一次编译后再次调用不需要再次编译 .

定义:
delimiter $$
create procedure 名字()
begin  # 开始
select * from cmd;  # 功能
end $$  # 结束
delimiter;

调用:
call p1()

删除:
drop procedure 名字;

带参数存储过程


MySql 支持 IN (传递给存储过程)

OUT (从存储过程传出)

INOUT (对存储过程传入和传出) 类型的参数

存储过程的代码位于 BEGIN 和 END 语句内 , 它们是一系列 SQL 语句 , 用来检索值 , 然后保存到相应的变量 (通过指定INTO关键字)

	delimiter $$
  create procedure p1(
      in m int,  # in表示这个参数必须只能是传入不能被返回出去
      in n int,  
      out res int  # out表示这个参数可以被返回出去,还有一个inout表示即可以传入也可以被返回出去
  )
  begin
      select tname from userinfo where id > m and id < n;
      set res=0;  # 用来标志存储过程是否执行
  end $$
  delimiter ;

# 针对res需要先提前定义
  set @res=10;  定义
  select @res;  查看
  call p1(1,5,@res)  调用
  select @res  查看

查看存储过程具体信息
	show create procedure pro1;
查看所有存储过程
	show procedure status;

函数


相当于内置函数

# 1.移除指定字符
Trim、LTrim、RTrim

# 2.大小写转换
Lower、Upper

# 3.获取左右起始指定个数字符
Left、Right

# 4.返回读音相似值(对英文效果)
Soundex
"""
eg:客户表中有一个顾客登记的用户名为J.Lee
		但如果这是输入错误真名其实叫J.Lie,可以使用soundex匹配发音类似的
		where Soundex(name)=Soundex('J.Lie')
"""

# 5.日期格式:date_format
'''在MySQL中表示时间格式尽量采用2022-11-11形式'''
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');

1.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(sub_time)=07;
# 更多日期处理相关函数 
	adddate	增加一个日期 
	addtime	增加一个时间
	datediff	计算两个日期差值
  ...

流程控制


# MySQL if判断
	if 条件 then
        子代码
  elseif 条件 then
        子代码
  else
        子代码
  end if;
  
# MySQL while循环
	DECLARE num INT ;
  SET num = 0 ;
  WHILE num < 10 DO
    SELECT num ;
    SET num = num + 1 ;
  END WHILE ;

索引


索引在MySQL中也就是‘键’,除了加速查询的效果之外还有额外的约束条件;回忆我们学过的键:

primary key 	主键  非空且唯一
unique	key		唯一键  唯一
index 	key   索引键  无约束条件

索引的基本用法

创建完表后:
# 主外键约束(注:project表中的id字段约束了此表中的projectid字段)
	FOREIGN KEY (projectid) REFERENCES project (id),
# 给字段创建了唯一索引(注:也可以在的创建字段时使用unique来创建唯一索引)
	UNIQUE INDEX (字段),
# 给字段创建普通索引
	INDEX (字段)

索引虽然方便了使用,但是会造成影响,因此不能大量的创建

影响:在表中有大量数据的前提下,创建索引速度会很慢;创建完索引后,对表的查询会更高效,而写的性能会降低

索引的底层数据结构是b+树(b树 红黑树 二叉树 b*树 b+树)

在每一个叶子节点做一个标记,把这些标记存起来,每次查的时候可以在查询根节点的时候从叶子节点也开始查

b树索引:计算机在读取数据的时候,都是按照块来读取的,大约4kb左右;而每次读取数据我们将其称为IO操作,如果计算机读取数据需要每次遍历所有块找数据,会造成资源极度浪费和时间浪费;而树索引极大的节约了计算机的工作时间和效率,这个工作就叫做索引。

聚集索引(primary key),辅助索引(unique key,index key)


作业

import pymysql

# 1.链接服务端
conn_obj = pymysql.connect(
    host='127.0.0.1',  # MySQL服务端的IP地址
    port=3306,  # MySQL默认PORT地址(端口号)
    user='root',  # 用户名
    password='',  # 密码  也可以简写 passwd
    database='name_data',  # 库名称  也可以简写 db
    charset='utf8',  # 字符编码 千万不要加杠utf-8
    autocommit=True
)

cursor = conn_obj.cursor(
    cursor=pymysql.cursors.DictCursor
)




sql2 = 'insert into user_data(name,pwd) values(%s, %s);'

sql3 = 'select name from name_data.user_data;'

sql4 = 'select * from user_data;'

# sql1 = 'create table user_data( id int primary key auto_increment,name varchar(32),pwd int)'
# 创建表




def register():
    name = input('请输入账号').strip()
    cursor.execute(sql3)
    res = cursor.fetchall()
    for i in res:
        if i['name'] == name:
            print('您的账户已存在')
            return
    else:
        pwd = input('请输入密码').strip()
        affect_row = cursor.execute(sql2, (name, pwd))
        if affect_row == 1:
            print('注册成功')
#
def log_in():
    name = input('输入您的账户').strip()
    pwd = int(input('输入您的密码').strip())
    cursor.execute(sql4)
    res = cursor.fetchall()
    for i in res:
        if i['name'] == name and i['pwd'] == pwd:
            print('登录成功')
            return
    else:
        print('账户或密码错误')



def run():
    number = input('输入1登录,输入2注册>>>:')
    if number == '1':
        log_in()
    elif number == '2':
        register()
    else:
        print('请输入正确的编号')


if __name__ == '__main__':
    run()

小结


努力学吧,调整好状态

posted @ 2022-05-09 22:37  Eason辰  阅读(59)  评论(0)    收藏  举报