核心作用:加速查找
在开发中会为那些经常会被搜索的列创建索引,以提高程序的响应速度,例如:手机号,邮箱,用户名…
B+Tree结构连接:https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
数据库的索引基于B+Tree的数据结构实现,但在创建数据库时,如果指定不同的引擎,底层使用的B+Tree结构的原理有些不同
数据和索引结构分开存储
create table 表名(
...
)engine=mysiam default charset=utf8;
数据的主键索引结构存储在一起
create table 表名(
...
)engine=innodb default charset=utf8;
在mysql文件存储的体现
root@192 userdb # pwd
/usr/local/mysql/data/userdb
root@192 userdb # ls -l
total 1412928
-- innodb
-rw-r----- 1 _mysql _mysql 8684 May 15 22:51 big.frm,表结构。
-rw-r----- 1 _mysql _mysql 717225984 May 15 22:51 big.ibd,数据和索引结构。
-rw-r----- 1 _mysql _mysql 8588 May 16 11:38 goods.frm
-rw-r----- 1 _mysql _mysql 98304 May 16 11:39 goods.ibd
-- mysiam
-rw-r----- 1 _mysql _mysql 8586 May 26 10:57 t2.frm,表结构
-rw-r----- 1 _mysql _mysql 0 May 26 10:57 t2.MYD,数据
-rw-r----- 1 _mysql _mysql 1024 May 26 10:57 t2.MYI,索引结构
企业中一般用innodb引擎(内部支持事务,行级锁,外键等特点),mysql5.5版本后默认是innodb
-- 显示表的创建信息
show create table users \G;
innodb引擎下,常见的索引类型:
主键索引
-- 方式一
create table 表名(
id int not null auto_increment primary key,
name varchar(32) not null
)
-- 方式二
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
primary key(id)
)
联合主键索引
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
primary key(id,name)
)
创建表之后添加主键索引
alter table 表名 add primary key(列名)
删除索引
alter table 表名 drop primary key;
注意:删除索引可能报错,自增列必须定义为键
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
-- 解决方式,用下面方法删除
alter table 表 change id id int not null;
唯一索引
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
-- ix_email是唯一索引的名字
unique ix_email (name)
)
联合唯一索引
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
unique ix_id_name (id,name)
)
创建表后创建唯一索引
create unique index 索引名 on 表名(列名);
删除唯一索引
drop unique index 索引名 on 表名;
普通索引
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
index ix_name (name)
)
联合普通索引
create table 表名(
id int not null auto_increment,
name varchar(32) not null,
email varchar(64) not null,
index ix_id_email (id,email)
)
创建表后创建普通索引
create index 索引名 on 表名(列名);
删除普通索引
drop index 索引名 on 表名;
实际开发,根据业务需求来决定是否创建相应的索引
创建索引后,查询时一定要命中索引
创建索引的优缺点
我们会在经常被搜索的列创建索引,从而提高程序的速度
CREATE TABLE `big` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`email` varchar(64) DEFAULT NULL,
`password` varchar(64) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`), -- 主键索引
UNIQUE KEY `big_unique_email` (`email`), -- 唯一索引
index `ix_name_pwd` (`name`,`password`) -- 联合索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8
一般情况下,通过索引列去搜索都可以命中
索引(通过索引结构加速查找)
-- 示例
select * from big where id=5;
select * from big where id>5;
select * from big where email='[email protected]';
select * from big where name='wxy' and password='123';
...
无法命中索引的情况
类型不一致
-- name是varchar类型不是int
select * from big where name=123; -- 未命中
-- 特殊的主键:
select * from big where id="123"; -- 命中
使用不等于
-- 找数据中不是wxy,要逐一对比查找
select * from big where name !='wxy'; -- 未命中
-- 特殊的主键:
select * from where id!=1; -- 命中
or,当or条件中有未建立索引的列才会失效
-- age 未创建索引
select * from big where id=1 or age=18; -- 未命中
-- 特殊的:
-- 后面又加了and
select * from where id=1 or age=18 and name='wxy';-- 命中
排序,当根据索引排序时,选择的映射不是索引,不走索引
-- 映射是所有的数据
select * from big order by name desc; -- 未命中
select name from big order by name desc; -- 命中
-- 特殊的主键
select * from big order by id desc; -- 命中
like,模糊匹配
select * from big where name like "%xy"; -- 未命中
select * from big where name like "_xy"; -- 未命中
select * from big where name like "w_y"; -- 未命中
-- 特别的【通配符在最后面才命中】:
select * from big where name like 'wx%'; -- 命中
select * from big where name like 'wx_'; -- 命中
使用函数
-- 要将每一个name翻转
select * from big where reverse(name)='wxy'; -- 未命中
-- 特别的
-- 直接将要对比的值翻转,在查找
select * from big where name=reverse('wxy'); -- 命中
最左前缀,如果使用联合索引,要遵循最左前缀原则
联合索引(name,password)
name and password -- 命中
name -- 命中
password -- 未命中
name or password -- 未命中
能够预判sql的执行(只能给一定的参考,不一定完全准确)
explain sql语句;
-- 示例
explain select * from big;
比较重要的是type,他是sql性能比较重要的标志,性能排序为:
all
ALL,全表扫描,数据表从头到尾找一遍(一般未命中索引,都会执行全表扫描)
select * from big;
-- 特别,如果有limit,找到之后就不找了
select * from big limit 1;
INDEX,全索引扫描,对索引从头到尾找一遍
-- name创建了索引
explain select name from big;
RANGE,对索引列进行范围查找
explain select * from big where id>10;
explain select * from big where id between 2 and 4;
explain select * from big where name>'wxy';
INDEX_MERGE,合并索引,使用多个单列索引搜索
explain select * from big where id=1 or name='wxy';
REF,根据索引直接去查找(非键)
select * from big where name='wxy';
EQ_REF,连表示时操作常见
explain select big,name,user.id from big left join users on big.age=user.id;
CONST,常量,表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,CONST表很快
-- 只能匹配到一行
explain select * from big where id=11;
explain select * from big where email='[email protected]';
SYSTEM,系统,表仅有一行(=系统表),这是CONST联接类型的一个特例
-- 表中只有一行数据
explain select * from(select * from big where id=1 limit 1) as A;
其他列
id
-- 查询顺序标识
select_type
-- 查询类型
SIMPLE 简单查询
PRIMARY 最外层查询
SUBQUERY 映射为子查询
DERIVED 子查询
UNION 联合
UNION RESULT 使用联合的结果
...
table
-- 正在访问的表名
partitions
-- 涉及的分区(MySQL支持将数据划分到不同的idb文件中,详单与数据的拆分)。 一个特别大的文件拆分成多个小文件(分区)。
possible_keys
-- 查询涉及到的字段上若存在索引,则该索引将被列出,即:可能使用的索引。
key
-- 显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。
-- 例如:有索引但未命中,则possible_keys显示、key则显示NULL。
key_len
-- 表示索引字段的最大可能长度。(类型字节长度 + 变长2 + 可空1)
-- 例如:key_len=195,类型varchar(64),195=64*3+2+1
ref
-- 连表时显示的关联信息。
-- 例如:A和B连表,显示连表的字段信息。
rows
-- 估计读取的数据行数(只是预估值)
filtered
-- 返回结果的行占需要读到的行的百分比。
explain select * from big where id=1; -- 100,只读了一个1行,返回结果也是1行。
explain select * from big where password="27d8ba90-edd0-4a2f-9aaf-99c9d607c3b3"; -- 10,读取了10行,返回了1行。
-- 注意:密码27d8ba90-edd0-4a2f-9aaf-99c9d607c3b3在第10行
extra
-- 该列包含MySQL解决查询的详细信息。
“Using index”
此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
“Using where”
这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
“Using temporary”
这意味着mysql在对查询结果排序时会使用一个临时表。
“Using filesort”
这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
“Range checked for each record(index map: N)”
这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
count(id) -- 求个数
max() -- 求最大值
min() -- 求最小值
avg() -- 求平均数
reverse() -- 翻转
concat(,) -- 字符串拼接
NOW() -- 获取当前时间
DATTE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s') 时间格式化
sleep(1) -- 睡眠
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'
创建函数
delimiter $$
-- 创建函数
create function f1(
-- 声明2个参数
i1 int,
i2 int)
returns int
BEGIN
declare num int;
declare maxId int;
select max(sid) from score into maxId;
set num = i1 + i2 + maxId;
return(num);
END $$
delimiter ;
mysql> delimiter $$
mysql> create function f1(
-> i1 int,
-> i2 int)
-> returns int
-> BEGIN
-> declare num int;
-> declare maxId int;
-> select max(sid) from score into maxId;
-> set num = i1 + i2 + maxId;
-> return(num);
-> END $$
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
执行函数
select f1(11,22);
select f1(11,sid),num from score;
mysql> select f1(11,22);
+-----------+
| f1(11,22) |
+-----------+
| 85 |
+-----------+
1 row in set (0.03 sec)
mysql> select f1(11,sid),num from score;
+------------+-----+
| f1(11,sid) | num |
+------------+-----+
| 64 | 10 |
.....
| 115 | 87 |
+------------+-----+
47 rows in set (0.01 sec)
删除函数
drop function f1;
mysql> drop function f1;
Query OK, 0 rows affected (0.02 sec)
存储过程,是一个存储在mysql中的sql语句集合,当主动去调用存储过程时,其中内部的sql语句1会按照逻辑执行
创建存储过程
delimiter $$
create procedure p1()
BEGIN
select * from class;
end $$
delimiter ;
mysql> delimiter $$
mysql> create procedure p1()
-> BEGIN
-> select * from student;
-> end $$
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
执行存储过程
call p1();
mysql> call p1();
+-----+--------+----------+--------+
| sid | gender | class_id | sname |
+-----+--------+----------+--------+
| 1 | 男 | 1 | 理解 |
| 2 | 女 | 1 | 钢蛋 |
| 3 | 男 | 1 | 张三 |
| 4 | 男 | 1 | 张一 |
| 5 | 女 | 1 | 张二 |
| 6 | 男 | 1 | 张四 |
| 7 | 女 | 2 | 铁锤 |
| 8 | 男 | 2 | 李三 |
| 9 | 男 | 2 | 李一 |
| 10 | 女 | 2 | 李二 |
| 11 | 男 | 2 | 李四 |
| 12 | 女 | 3 | 如花 |
| 13 | 男 | 3 | 刘三 |
| 14 | 男 | 3 | 刘一 |
| 15 | 女 | 3 | 刘二 |
| 16 | 男 | 3 | 刘四 |
+-----+--------+----------+--------+
16 rows in set (0.02 sec)
Query OK, 0 rows affected (0.10 sec)
python执行
import pymysql
conn=pymysql.connect(host='127.0.0.1',port=3306,user='root',password='wxy575254',db='day27db',charset='utf8')
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.callproc('p1')
result=cursor.fetchall()
cursor.close()
conn.close()
print(result)
#[{'cid': 1, 'caption': '三年二班'}, {'cid': 2, 'caption': '三年三班'}, {'cid': 3, 'caption': '一年二班'}, {'cid': 4, 'caption': '二年九班'}]
删除存储过程
drop procedure p1;
mysql> drop procedure p1;
Query OK, 0 rows affected (0.02 sec)
存储过程的参数可以有如下三种:
-- 创建
delimiter $$
create procedure p2(
in i1 int,
in i2 int,
inout i3 int,
out r1 int
)
begin
declare temp1 int;
declare temp2 int default 0;
set temp1=1;
set r1=i1+i2+temp1+temp2;
set i3=i3+100;
end $$
delimiter $$
mysql> delimiter $$
mysql> create procedure p2(
-> in i1 int,
-> in i2 int,
-> inout i3 int,
-> out r1 int
-> )
-> begin
-> declare temp1 int;
-> declare temp2 int default 0;
-> set temp1=1;
-> set r1=i1+i2+temp1+temp2;
-> set i3=i3+100;
-> end $$
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
-- 执行
set @t1=4;
set @t2=0;
call p2(1,2,@t1,@t2);
select @t1,@t2;
mysql> set @t1=4;
Query OK, 0 rows affected (0.00 sec)
mysql> set @t2=0;
Query OK, 0 rows affected (0.00 sec)
mysql> call p2(1,2,@t1,@t2);
Query OK, 0 rows affected (0.00 sec)
mysql> select @t1,@t2;
+------+------+
| @t1 | @t2 |
+------+------+
| 104 | 4 |
+------+------+
1 row in set (0.00 sec)
python执行
import pymysql
conn=pymysql.connect(host='127.0.0.1',port=3306,user='root',password='',db='day27db',charset='utf8')
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)
#执行存储过程
cursor.callproc('p2',args=(1,22,3,4))
#获取执行完存储的参数
cursor.execute('select @_p2_0,@_p2_1,@_p2_3,@_p2_3')
result=cursor.fetchall()
cursor.close()
conn.close()
print(result)
#[{'@_p2_0': 1, '@_p2_1': 22, '@_p2_3': 24, '.@_p2_3': 24}]
-- 创建
delimiter $$
create procedure p3(
in n1 int,
inout n2 int,
out n3 int
)
begin
set n2=n1+100;
set n3=n2+n1+100;
select * from student;
end $$
delimiter ;
mysql> delimiter $$
mysql> create procedure p3(
-> in n1 int,
-> inout n2 int,
-> out n3 int
-> )
-> begin
-> set n2=n1+100;
-> set n3=n2+n1+100;
-> select * from student;
-> end $$
Query OK, 0 rows affected (0.01 sec)
mysql> delimiter ;
-- 执行
set @t1=4;
set @t2=0;
call p3(1,@t1,@t2);
select @t1,@t2; -- 获取返回值
mysql> set @t1=4;
Query OK, 0 rows affected (0.00 sec)
mysql> set @t2=0;
Query OK, 0 rows affected (0.00 sec)
mysql> call p3(1,@t1,@t2);
+-----+--------+----------+--------+
| sid | gender | class_id | sname |
+-----+--------+----------+--------+
| 1 | 男 | 1 | 理解 |
| 2 | 女 | 1 | 钢蛋 |
| 3 | 男 | 1 | 张三 |
| 4 | 男 | 1 | 张一 |
| 5 | 女 | 1 | 张二 |
| 6 | 男 | 1 | 张四 |
| 7 | 女 | 2 | 铁锤 |
| 8 | 男 | 2 | 李三 |
| 9 | 男 | 2 | 李一 |
| 10 | 女 | 2 | 李二 |
| 11 | 男 | 2 | 李四 |
| 12 | 女 | 3 | 如花 |
| 13 | 男 | 3 | 刘三 |
| 14 | 男 | 3 | 刘一 |
| 15 | 女 | 3 | 刘二 |
| 16 | 男 | 3 | 刘四 |
+-----+--------+----------+--------+
16 rows in set (0.00 sec)
Query OK, 0 rows affected (0.05 sec)
mysql> select @t1,@t2;
+------+------+
| @t1 | @t2 |
+------+------+
| 101 | 202 |
+------+------+
1 row in set (0.00 sec)
python执行
import pymysql
conn=pymysql.connect(host='127.0.0.1',port=3306,user='root',password='',db='day27db',charset='utf8')
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)
#执行存储过程
cursor.callproc('p3',args=(22,3,4))
#得到执行存储中的结果集
table=cursor.fetchall()
#获取执行完存储的参数
cursor.execute('select @_p3_0,@_p3_1,@_p3_2')
result=cursor.fetchall()
cursor.close()
conn.close()
print(result)
#[{'@_p3_0': 22, '@_p3_1': 122, '@_p3_2': 244}]
print(table)
#[{'sid': 1, 'gender': '男', 'class_id': 1, 'sname': '理解'}, {'sid': 2, 'gender': '女', 'class_id': 1, 'sname': '钢蛋'}, {'sid': 3, 'gender': '男', 'class_id': 1, 'sname': '张三'}, {'sid': 4, 'gender': '男', 'class_id': 1, 'sname': '张一'}, {'sid': 5, 'gender': '女', 'class_id': 1, 'sname': '张二'}, {'sid': 6, 'gender': '男', 'class_id': 1, 'sname': '张四'}, {'sid': 7, 'gender': '女', 'class_id': 2, 'sname': '铁锤'}, {'sid': 8, 'gender': '男', 'class_id': 2, 'sname': '李三'}, {'sid': 9, 'gender': '男', 'class_id': 2, 'sname': '李一'}, {'sid': 10, 'gender': '女', 'class_id': 2, 'sname': '李二'}, {'sid': 11, 'gender': '男', 'class_id': 2, 'sname': '李四'}, {'sid': 12, 'gender': '女', 'class_id': 3, 'sname': '如花'}, {'sid': 13, 'gender': '男', 'class_id': 3, 'sname': '刘三'}, {'sid': 14, 'gender': '男', 'class_id': 3, 'sname': '刘一'}, {'sid': 15, 'gender': '女', 'class_id': 3, 'sname': '刘二'}, {'sid': 16, 'gender': '男', 'class_id': 3, 'sname': '刘四'}]
事务,成功都成功,失败都失败
delimiter $$
create procedure p4(
out p_return_code tinyint
)
begin
declare exit handler for sqlexception
begin
set p_return_code=1;
rollback;
end;
declare exit handler for sqlwarning
begin
set p_return_code=2;
rollback;
end;
start transaction;
delete from student;
insert into class(caption)values('all');
commit;
set p_return_code=0;
end $$
delimiter ;
mysql> delimiter $$
mysql> create procedure p4(
-> out p_return_code tinyint
-> )
-> begin
-> declare exit handler for sqlexception
-> begin
-> set p_return_code=1;
-> rollback;
-> end;
-> declare exit handler for sqlwarning
-> begin
-> set p_return_code=2;
-> rollback;
-> end;
-> start transaction;
-> delete from student;
-> insert into class(caption)values('all');
-> commit;
-> set p_return_code=0;
-> end $$
Query OK, 0 rows affected (0.02 sec)
mysql> delimiter ;
set @ret=100;
call p4(@ret);
select @ret;
mysql> set @ret=100;
Query OK, 0 rows affected (0.00 sec)
mysql> call p4(@ret);
Query OK, 0 rows affected (0.01 sec)
mysql> select @ret;
+------+
| @ret |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
python执行
import pymysql
conn=pymysql.connect(host='127.0.0.1',port=3306,user='root',password='',db='day27db',charset='utf8')
cursor=conn.cursor(cursor=pymysql.cursors.DictCursor)
#执行存储过程
cursor.callproc('p4',args=(100))
#获取执行完存储的参数
cursor.execute('select @_p4_0')
result=cursor.fetchall()
cursor.close()
conn.close()
print(result)
delimiter $$
create procedure p5()
begin
declare cid int;
declare caption varchar(50);
declare done int default false;
declare my_cursor cursor for select cid,caption from class;
declare continue handler for not found set done =TRUE;
open my_cursor;
xxoo:loop
fetch my_cursor into cid,caption;
if done then
leave xxoo;
end if;
insert into teacher(tname) values(caption);
end loop xxoo;
close my_cursor;
end $$
delimiter ;
mysql> delimiter $$
mysql> create procedure p5()
-> begin
-> declare cid int;
-> declare caption varchar(50);
-> declare done int default false;
-> declare my_cursor cursor for select cid,caption from class;
-> declare continue handler for not found set done =TRUE;
-> open my_cursor;
-> xxoo:loop
-> fetch my_cursor into cid,caption;
-> if done then
-> leave xxoo;
-> end if;
-> insert into teacher(tname) values(caption);
-> end loop xxoo;
-> close my_cursor;
-> end $$
Query OK, 0 rows affected (0.01 sec)
-- done为false,没有值,插不进去,报错
call p5();
mysql> call p5();
ERROR 1048 (23000): Column 'tname' cannot be null
视图其实是一个虚拟表(非真实存在),本质是(根据sql语句获取动态的数据集,并为其命名),用户使用时只需要使用【名称】即可获取数据集
select
*
from
(select nid,name from tb1 where nid>2) as A
where
A.name>'wxy';
创建视图
create view A as select nid,name from tb1 where nid>2;
使用视图
SELECT * from A;
删除视图
drop view A;
修改视图
alter view A as sql语句;
注意,基于视图只能查询,不能执行增加,修改,删除,如果源表发生变化,试图也会发生变化
对于某个表进行【删除/增加/修改】操作的前后如果希望触发某个特定的行为时,可使用触发器
创建触发器
插入前
create trigger tri_before_insert_tb1 before insert on tb1 for each row
begin
...
end
插入后
create trigger tri_after_insert_tb1 after insert on tb1 for each row
begin
...
end
删除前
create trigger tri_before_delete_tb1 after delete on tb1 for each row
begin
...
end
删除后
create trigger tri_after_delete_tb1 after delete on tb1 for each row
begin
...
end
更新前
create trigger tri_before_update_tb1 after update on tb1 for each row
begin
...
end
更新后
create trigger tri_after_update_tb1 after update on tb1 for each row
begin
...
end
删除触发器
drop trigger tri_after_insert_tb1;
示例
delimiter $$
create trigger tri_before_insert_tb1 before insert on tb1 for each row
begin
-- 插入的是new,新数据
-- 如果插入的name='wxy',就在t2表中插入
if new.name='wxy' then
insert into t2 (name) values(new.id)
end if;
end $$
delimiter ;
delimiter $$
create trigger tri_after_delete_tb1 after delete on tb1 for each row
begin
-- 删除的是old,旧数据
-- 如果删除的name='wxy',就在t2表中插入
if old.name='wxy' then
insert into t2 (name) values(old.id)
end if;
end
delimiter ;
注意;NEW表示新数据,OLD表示旧数据