前言:
数据库相关的操作
1.SQL语句 *****(MySql(一)已经介绍);
2.利用mysql内部提供的功能(视图、触发器、函数、存储过程;
一、视图:
把经常使用的查询结果,做成临时视图表,保存方便反复使用;
1、创建视图:
CREATE VIEW zhanggen as SELECT * FROM score;
2、查看视图:
SELECT * FROM zh;
3、删除视图
drop view zh
二、触发器
当对某张表做:增删改操作时,可以使用触发器自定义关联行为;
1.插入前触发器:
格式:创建触发器 名称 BEFORE INSERT(操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN
... 触发器
END
2、插入后 触发器
格式:创建触发器 名称 AFTER INSERT(操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
...触发器
END
3、删除前触发器
格式:创建触发器 名称 BEFORE DELETE(操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
BEGIN
...触发器
END
4、删除后触发器
格式:创建触发器 名称 AFTER DELETE (操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
BEGIN
...
END
5、更新前触发器
格式:创建触发器 名称 BEFORE UPDATE (操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
BEGIN
...
END
6、更新后触发器
格式:创建触发器 名称 AFTER UPDATE(操作 前/后) on 表 FOR EACH ROW(没插入一条数据触发器执行一次)
CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
BEGIN
...
END
7、
NEW,代指新数据 (更新)
OLD,代指老数据 (删除)
delimiter //:修改SQL语句的结束符
insert into tb (....)
delimiter //
create trigger t1 BEFORE INSERT on student for EACH ROW
BEGIN
INSERT into teacher(tname) values(NEW.sname);
INSERT into teacher(tname) values(NEW.sname);
INSERT into teacher(tname) values(NEW.sname);
INSERT into teacher(tname) values(NEW.sname);
END //
delimiter ;
insert into student(gender,class_id,sname) values('女',1,'陈涛'),('女',1,'张根');
三、函数
1、SQL语句的内置函数(max(),min(),count()...)
CHAR_LENGTH(str)
返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。 CONCAT(str1,str2,...)
字符串拼接
如有任何一个参数为NULL ,则返回值为 NULL。
CONCAT_WS(separator,str1,str2,...)
字符串拼接(自定义连接符)
CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。 CONV(N,from_base,to_base)
进制转换
例如:
SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示 FORMAT(X,D)
将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。
例如:
SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
INSERT(str,pos,len,newstr)
在str的指定位置插入字符串
pos:要替换位置其实位置
len:替换的长度
newstr:新字符串
特别的:
如果pos超过原字符串长度,则返回原字符串
如果len超过原字符串长度,则由新字符串完全替换
INSTR(str,substr)
返回字符串 str 中子字符串的第一个出现位置。 LEFT(str,len)
返回字符串str 从开始的len位置的子序列字符。 LOWER(str)
变小写 UPPER(str)
变大写 LTRIM(str)
返回字符串 str ,其引导空格字符被删除。
RTRIM(str)
返回字符串 str ,结尾空格字符被删去。
SUBSTRING(str,pos,len)
获取字符串子序列 LOCATE(substr,str,pos)
获取子序列索引位置 REPEAT(str,count)
返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
若 count <= 0,则返回一个空字符串。
若str 或 count 为 NULL,则返回 NULL 。
REPLACE(str,from_str,to_str)
返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
REVERSE(str)
返回字符串 str ,顺序和字符顺序相反。
RIGHT(str,len)
从字符串str 开始,返回从后边开始len个字符组成的子序列 SPACE(N)
返回一个由N空格组成的字符串。 SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。 mysql> SELECT SUBSTRING('Quadratically',5);
-> 'ratically' mysql> SELECT SUBSTRING('foobarbar' FROM 4);
-> 'barbar' mysql> SELECT SUBSTRING('Quadratically',5,6);
-> 'ratica' mysql> SELECT SUBSTRING('Sakila', -3);
-> 'ila' mysql> SELECT SUBSTRING('Sakila', -5, 3);
-> 'aki' mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
-> 'ki' TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。 mysql> SELECT TRIM(' bar ');
-> 'bar' mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
-> 'barxxx' mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
-> 'bar' mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
-> 'barx' 部分内置函数
需要记住:
SELECT CURDATE()查询当前时间;
data_format(ctime,"%Y-%m"):设置时间类型数据的格式;(在内存修改,不会改掉原数据;(通过月group by 就可设计博客园,每月博客统计的效果;)
2、自定义函数:
注意 1、函数必须有返回值 2、函数体不能出现select * from 表
自定义函数(有返回值):
delimiter \\
create function f1(
i1 int,
i2 int)
returns int
BEGIN
declare num int default 0;
set num = i1 + i2;
return(num);
END \\
delimiter ;
SELECT f1(1,100);
调用:SELECT f1(1,100);
3、调用函数
执行函数 select 函数名();
四、普通存储过程
1.什么是存储过程:
在数据库里保存别名 -------《封装一堆SQL语句操作》,开发人员直接调用别名,无需要程序里写SQL语句了;
2.功能:
替代程序员写SQL语句;
3.公司中常见的 数据库使用场景:
方式1:
在数据库里面:保存存储过程别名;
在程序里面: 直接调用 存储过程别名;
方式2:
在程序里面语句写 SQL
方式3:
在程序里写 类和对象;(通过程序中写好的库,转换成SQL语句)
4、存储过程的定义:
4.1. 简单无参数存储过程
create procedure p1()
BEGIN
select * from student;
INSERT into teacher(tname) values("ct");
END
call p1()
cursor.callproc('p1')
4.2、带参数的存储过程
delimiter //
create procedure p3(
in n1 int,
inout n2 int
)
BEGIN
set n2 = 123123;
select * from student where sid > n1;
END //
delimiter ;
5、存储过程的调用:
5.1.在mysql端调用存储过程别名:
set @v1 = 10;(设置变量(session))在session级别创建变量:set @变量名
call p2(12,@v1) 调用存储过程,返回存储过程执行的结果集;
select @v1; 查看了out参数返回的值
5.2Python调用存储过程别名:
查看存储过程的结果集:
cursor.callproc('p3',(12,2))
r1 = cursor.fetchall()
print(r1)
查看out参数返回的值:注意
cursor.execute('select @_p3_0,@_p3_1')
r2 = cursor.fetchall()
print(r2)
6、参数 in、out、inout参数的意义
in:普通值,给存储过程内部传值,在存存储过程外部无法获取;
out:变量,给存储过程外部输出值,在存储过程内部无法使用;
inout变量:既能在存储过程内部使,还可以有返回值;
7、大波课上一问:为什么有存储过程执行完了返回了结果集,还需要 out参数的返回值?
delimiter //
create procedure p3(
in n1 int,
out n2 int
out n3 int)
BEGIN
insert into vv(..) set n2= 1
insert into vv(..)
insert into vv(..)
insert into vv(..)
insert into vv(..)
insert into vv(..) set n3=6
END //
delimiter;
利用out返回值,判断存储过程的执行状态,n2=1 执行到了insert1 n3=6执行到了insert=6;
8、阿根课上一疑?存储过程封装了SQL语句,和TND上面说函数不是一样一样滴吗?
答:不是的
1、函数不可以封装 查询类型的SQL语句
3、参数不一样 存储过程的函数 分in/out/inout三类,函数没有
2、调用方式不一样(函数select,存储过程call)
五、支持事务的存储过程
delimiter //
create procedure p4(
out status int
)
BEGIN
1. 声明如果出现异常则执行{
set status = 1;
rollback;
} 开始事务
-- 由秦兵账户减去100
-- 方少伟账户加90
-- 张根账户加10
commit;
结束 set status = 2; END //
delimiter ; ===============================
delimiter \\
create PROCEDURE p5(
OUT p_return_code tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
set p_return_code = 1;
rollback;
END; START TRANSACTION;
DELETE from tb1;
insert into tb2(name)values('seven');
COMMIT; -- SUCCESS
set p_return_code = 2; END\\
delimiter ;
六. 游标+存储过程(相当于Python的for循环,对表中列,一一设置。)
delimiter //
create procedure p6()
begin
declare row_id int; -- 自定义变量1
declare row_num int; -- 自定义变量2
declare done INT DEFAULT FALSE;
declare temp int; declare my_cursor CURSOR FOR select id,num from A;
declare CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; open my_cursor;
xxoo: LOOP
fetch my_cursor into row_id,row_num;
if done then
leave xxoo;
END IF;
set temp = row_id + row_num;
insert into B(number) values(temp);
end loop xxoo;
close my_cursor; end //
delimter
七. 存储过程+动态执行SQL(防SQL注入)
delimiter //
create procedure p7(
in tpl varchar(255),
in arg int
)
begin
1. 预检测某个东西 SQL语句合法性
2. SQL =格式化 tpl + arg
3. 执行SQL语句 set @xo = arg;
PREPARE xxx FROM 'select * from student where sid > ?';
EXECUTE xxx USING @xo;
DEALLOCATE prepare prod;
end //
delimter ; call p7("select * from tb where id > ?",9) ===> delimiter \\
CREATE PROCEDURE p8 (
in nid int
)
BEGIN
set @nid = nid;
PREPARE prod FROM 'select * from student where sid > ?';
EXECUTE prod USING @nid;
DEALLOCATE prepare prod;
END\\
delimiter ;
八、Python的操作MySQL (pymysql模块)
1、用户、密码在mysql,python实现用户登录
import pymysql
user=input("username:").strip()
pwd=input("password:").strip()
conn=pymysql.connect(host="192.168.182.128",user="eric",password="",database="day58") #数据库连接对象
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor) #创建游标对象(打开数据库的小手)
# cursor=pymysql.cursors.DictCursor参数会把fetch到的结果变成,字典套元组的格式;
sql="select * from user_info where name= %s and passwd= %s"
cursor.execute(sql,[user,pwd]) # pymysql的excute([参数1,参数2])方法,会自动帮我们做字符串拼接,并检查SQL注入
res=cursor.fetchone()
print(res)
print("登录成功") if res else print("用户/密码错误")
cursor.close()
conn.close()
2、插入300W条数据
import pymysql
conn=pymysql.connect(host="192.168.182.128",user="eric",password="",database="day61")
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)
for i in range(3000000):
i=str(i)
name=i+'alex'
gender="man"
email=name+"@163.com"
sql = "insert into user(name,gender,email)values(%s,%s,%s)"
cursor.execute(sql,[name,gender,email])
if cursor.lastrowid%500000==0:
print(cursor.lastrowid) # cursor.lastrowid 属性获取最后一条数据的自增ID
conn.commit() # 注意不要忘记:conn.commit()提交了事物,数据库中的数据才会更新;
else:print("插入完成!")
cursor.close() # 最后记得:关闭游标、关闭连接
conn.close()
九、数据库操作总结:
1、SQL语句(MySQL一博客)重要常用
2、利用mysql内部提供的功能(视图、触发器、函数、存储过程)