[MySQL数据库之Navicat.pymysql模块、视图、触发器、存储过程、函数、流程控制]
Navicat
Navicat是一套快速、可靠并价格相当便宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。它的设计符合数据库管理员、开发人员及中小企业的需要。Navicat 是以直觉化的图形用户界面而建的,让你可以以安全并且简单的方式创建、组织、访问并共用信息。
我们在终端操作MySQL没有自动提示,也无法自动保存等等不方便开发,Navicat内部封装了所有的操作数据库命令,用户在使用它的时候只需要鼠标点点点即可完成操作,无需书写sql语句。
pymysql模块
下载安装pymysql模块
pip3 install pymysql
往ttt表插入数据
连接、执行sql、关闭(游标)
# pip3 install pymysql
# 导入模块
import pymysql
# 连接
conn = pymysql.connect(host="127.0.0.1",port=3306,database='db3',user="root",password="111")
# 创建游标(指定参数)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行sql语句,返回sql查询成功的记录行数,并打印
rows = cursor.execute("select * from ttt;")
print(rows)
# 拿到sql语句查询的数据结果并打印
res = cursor.fetchall()
print(res)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()
'''
注意:默认情况下,我们获取到的返回值是元组,只能看到每行的数据,却不知道每一列代表的是什么,
这个时候可以使用以下方式来返回字典,每一行的数据都会生成一个字典:
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
在实例化的时候,将属性cursor设置为pymysql.cursors.DictCursor
ps:查询是有结果返回的,执行增、删、改就不需要用到fetchall了
'''
execute()之slq注入:连接,用户登录认证
创建user表
# 导入模块
import pymysql
# 连接
conn = pymysql.connect(host="127.0.0.1",port=3306,database='db3',user="root",password="111")
# 创建游标(指定参数)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 用户输入用户名,密码
user = input('请输入用户名:').strip()
pwd = input('请输入密码:').strip()
# execute帮我们做字符串拼接,我们无需且一定不能为%s加引号
rows = cursor.execute('select * from user where username = %s and password = %s',args=(user,pwd))
# 判断
if rows:
print('登录成功!')
else:
print('用户名或密码错误!')
# 关闭游标连接
cursor.close()
conn.close()
增、改、删 conn.commit()
在数据库里增 删 改 的时候 必须要进行提交,否则插入的数据不生效。
# 导入模块
import pymysql
# 连接
conn = pymysql.connect(host="127.0.0.1",port=3306,database='db3',user="root",password="111")
# 游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 以下操作演示还是参照db3库下的user表
# 操作:增(插入数据也可同时插入多条)
cursor.execute("insert into user values(5,'haha','123'),(6,'hanzi','222');")
# 操作:改(将id为3的名字改为lili)
cursor.execute("update user set username = 'lili' where id = 3;")
# 操作:删(删除id为2的一行记录)
rows = cursor.execute("delete from user where id = 2;")
print(rows)
# 操作任意增删改操作一定记得commit
conn.commit()
# 关闭游标和连接
cursor.close()
conn.close()
查:fetchone、fetchmany、fetchall
fetchone():获取下一行的数据,第一次为首行。
fetchall():获取所有行数数据。
fetchmany(2):获取2行数据.
# 导入模块
import pymysql
# 连接
conn = pymysql.connect(host="127.0.0.1",port=3306,database='db3',user="root",password="111")
# 游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 执行sql语句查询整张表的数据(打印只显示行数)
rows = cursor.execute("select * from user;")
print(rows)
# fetchall():获取所有行数数据。
res = cursor.fetchall()
print(res)
# fetchone():获取下一行的数据,第一次为首行
print(cursor.fetchone()) # 查询第一行
print(cursor.fetchone()) # 查询第二行
print(cursor.fetchone()) # 查询第三行
# fetchmany(2):获取3行数据.用列表套字典显示
print(cursor.fetchmany(2))
# 打印结果
'''
{'id': 1, 'username': 'geng', 'password': '234'}
{'id': 3, 'username': 'lili', 'password': '111'}
{'id': 4, 'username': 'liu', 'password': '222'}
[{'id': 5, 'username': 'haha', 'password': '123'},
{'id': 6, 'username': 'hanzi', 'password': '222'}]
'''
# 控制游标移动
# cursor.scroll(3,mode='absolute') # 绝对位置移动
# cursor.scroll(3,mode='relative') # 相对当前位置移动
print(cursor.fetchone())
print(cursor.fetchone())
print(cursor.fetchone())
cursor.scroll(2,mode='relative')
cursor.scroll(2,mode='absolute') # 永远参照开头移动
print(cursor.fetchone())
cursor.close()
conn.close()
lastrowid()获取插入的最后一条数据的自增ID
# 导入模块
import pymysql
# 连接
conn = pymysql.connect(host="127.0.0.1",port=3306,database='db3',user="root",password="111")
# 游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 插入sql语句
sql='insert into user(username,password) values("xxx","123");'
rows=cursor.execute(sql)
print(cursor.lastrowid) # 在插入语句后查看
# 一定要commit
conn.commit()
# 关闭游标和连接
cursor.close()
conn.close()
视图
概念:通过查询得到的一张虚拟表,然后保存下来就是视图
视图的好处:如果要频繁使用某张虚拟表,那么就可以保存为视图,以后查找就直接拿这个视图就会非常方便
视图语法规则:
# 新增视图
create view emp_dep_view as
select employee.*,department.name as depname from employee inner join department
on employee.dep_id = department.id;
# 修改视图
alter view emp_dep_view as
select employee.*,department.name as depname from employee inner join department
on employee.dep_id = department.id;
# 删除视图
drop view emp_dep_view;
视图需要注意的点:
1、视图在硬盘中只有表结构文件,没有表数据文件,数据取自原查询的表
2、视图常用于查询,尽量不要修改视图表中的数据,修改数据可能会导致原表数据出现问题
触发器
概念:在对某张表进行增删改的操作时会自动触发另外一部分功能的执行的行为被称为触发器
为什么用触发器:触发器专门针对我们对某张表的增删改的行为,实际需求中我们可能需要监控这张表的操作并执行一些其他功能,这时候使用触发器将会非常方便。
创建触发器语法规则:
# 针对插入
create trigger tri_after_insert_t1 after insert on 表名 for each row
begin
sql代码。。。
end
create trigger tri_after_insert_t2 before insert on 表名 for each row
begin
sql代码。。。
end
# 针对删除
create trigger tri_after_delete_t1 after delete on 表名 for each row
begin
sql代码。。。
end
create trigger tri_after_delete_t2 before delete on 表名 for each row
begin
sql代码。。。
end
# 针对修改
create trigger tri_after_update_t1 after update on 表名 for each row
begin
sql代码。。。
end
create trigger tri_after_update_t2 before update on 表名 for each row
begin
sql代码。。。
end
伪案例:
# 案例
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 // # 将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 ; # 结束之后记得再改回来,不然后面结束符就都是$$了
#往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志
INSERT INTO cmd (
USER,
priv,
cmd,
sub_time,
success
)
VALUES
('egon','0755','ls -l /etc',NOW(),'yes'),
('egon','0755','cat /etc/passwd',NOW(),'no'),
('egon','0755','useradd xxx',NOW(),'no'),
('egon','0755','ps aux',NOW(),'yes');
# 查询errlog表记录
select * from errlog;
# 删除触发器
drop trigger tri_after_insert_cmd;
存储过程
概念:存储过程包含一堆sql语句,可以通过对存储过程的名字来调用执行内部语句,类似于其他编程语言中的函数
存储过程的三种开发模型:
第一种:
应用程序:只需要开发应用程序的逻辑
mysql:事先编写好存储过程,供应用程序随时调用
优点:开发效率和执行效率高
缺点:人为因素较多,跨部门沟通等,扩展性较差
第二种:
应用程序:除了要开发应用程序逻辑,还需要编写原生的sql语句
优点:扩展性较高,都根据mysql语法规则来编写sql语句即可
缺点:编写原生sql语句十分复杂,并且要考虑到sql语句优化的问题,这就导致了开发效率和执行效率降低的问题
第三种:
应用程序:只考虑应用程序的逻辑,不需要管SQL语句的实现,基于第三方的工具和库
优点:开发效率高,直接调用已封装好的功能和方法就好,有更好的兼容性
缺点:执行效率比较低,执行效率不如第二种
如何创建存储过程:
# 存储过程在那个库下创建即在哪个库下面生效,不是全局的
# 1、直接在mysql中调用
set @res=10 # res的值是用来判断存储过程是否被执行成功的依据,所以需要先定义一个变量@res存储10
call p1(2,4,10); # 报错
call p1(2,4,@res);
# 查看结果
select @res; # 执行成功,@res变量值发生了变化
# 2、在python程序中调用
pymysql链接mysql
产生的游表cursor.callproc('p1',(2,4,10)) # 内部原理:@_p1_0=2,@_p1_1=4,@_p1_2=10;
cursor.excute('select @_p1_2;')
# 3、存储过程与事务使用举例(了解)
delimiter //
create PROCEDURE p5(
OUT p_return_code tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
set p_return_code = 1;
rollback;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
set p_return_code = 2;
rollback;
END;
START TRANSACTION;
update user set balance=900 where id =1;
pdate user123 set balance=1010 where id = 2;
pdate user set balance=1090 where id =3;
COMMIT;
-- SUCCESS
set p_return_code = 0; #0代表执行成功
END //
delimiter ;
函数
注意与存储过程的区别,mysql内置的函数只能在sql语句中使用!
参考博客:http://www.cnblogs.com/linhaifeng/articles/7495918.html#_label2
需要掌握函数:date_format
# 1 基本使用
mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
-> 'Sunday October 2009'
mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
-> '%D %y %a %d %m %b %j');
-> '4th 00 Thu 04 10 Oct 277'
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
-> '%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
-> '1998 52'
mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
-> '00'
# 2 准备表和记录
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');
# 3. 提取sub_time字段的值,按照格式后的结果即"年月"来分组
SELECT DATE_FORMAT(sub_time,'%Y-%m'),COUNT(1) FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');
# 结果
+-------------------------------+----------+
| DATE_FORMAT(sub_time,'%Y-%m') | COUNT(1) |
+-------------------------------+----------+
| 2015-03 | 2 |
| 2016-07 | 4 |
| 2017-03 | 3 |
+-------------------------------+----------+
3 rows in set (0.00 sec)
流程控制
# 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 ;
END //
delimiter ;