视图
概念:给某个查询语句设置别名,创建这个别名的过程就叫创建视图,这个别名就是视图;注意:视图其实就是给一个select创建别名,在调用的时候才会生效,所以如果源数据内容更改,则视图内容同样会跟着改变
创建格式 create view 视图名称 as SQL; 修改视图 alter view 视图名称 as 新SQL; 删除视图 drop view 视图名称; 例如:
create view v1 as select * from student where sid > 10;
触发器
概念:SQL触发器,是一种特殊类型的存储过程,不由用户直接调用。它在指定的表中的数据发生变化时自动生效。唤醒调用触发器以响应 INSERT、UPDATE 或 DELETE 语句。将触发器和触发它的语句作为可在触发器内回滚的单个事务对待。如果检测到严重错误(例如,磁盘空间不足),则整个事务即自动回滚。常常用于强制业务规则和数据完整性。
创建格式 delimiter // # 更改断句符 create trigger 触发器名称 BEFORE INSERT on 表名 for EACH ROW # trigger 后面跟触发器名字,表名是告知触发器要在那个表的内容有变动之前做操作,EACH ROW是数据变动一行就触发一次触发器 BEGIN INSERT into teacher(tname) values(NEW.sname); END // # 还原断句符 delimiter ;
创建数据之前触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt1 BEFORE INSERT on t1 for EACH ROW BEGIN insert into t2(py) values(NEW.name); END \ delimiter ; insert into t1(name) values('梁晓');
创建数据之后触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt2 AFTER INSERT on t1 for EACH ROW BEGIN insert into t2(py) values(NEW.name); END \ delimiter ; insert into t1(name) values('王文杰');
删除数据之前触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt2 BEFORE DELETE on t1 for EACH ROW BEGIN insert into t2(py) values(NEW.name); END \ delimiter ; insert into t1(name) values('王文杰');
删除数据之后触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt2 AFTER DELETE on t1 for EACH ROW BEGIN insert into t2(py) values(OLD.name); END \ delimiter ; insert into t1(name) values('王文杰');
更新数据之前触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt2 BEFORE UPDATE on t1 for EACH ROW BEGIN insert into t2(py) values(NEW.name); END \ delimiter ; insert into t1(name) values('王文杰');
更新数据之后触动触发器 create table t1(id int auto_increment key,name varchar(10) not null)engine=innodb; create table t2(id int auto_increment key,py varchar(10) not null)engine=innodb; delimiter \ create trigger tt2 AFTER UPDATE on t1 for EACH ROW BEGIN insert into t2(py) values(OLD.name); END \ delimiter ; insert into t1(name) values('王文杰');
注意:这里的NEW代表的是新数据,OLD代表的是旧数据
函数
内置函数
mysql中有内置函数,也可以自定义函数,函数用来完成用户的一些特定功能;下面附关于内置函数的教程地址。
https://dev.mysql.com/doc/refman/5.7/en/functions.html(官方地址)
https://www.runoob.com/mysql/mysql-functions.html (中文教程)
函数的使用格式
select Function(); # Function是函数名,函数名后面可以不跟载体,直接加入参数或者不加
有一个比较要注意的内置date_format,下面附关于这个内置函数的一些相关参数:
%a Abbreviated weekday name (Sun..Sat) %b Abbreviated month name (Jan..Dec) %c Month, numeric (0..12) %D Day of the month with English suffix (0th, 1st, 2nd, 3rd, …) %d Day of the month, numeric (00..31) %e Day of the month, numeric (0..31) %f Microseconds (000000..999999) %H Hour (00..23) %h Hour (01..12) %I Hour (01..12) %i Minutes, numeric (00..59) %j Day of year (001..366) %k Hour (0..23) %l Hour (1..12) %M Month name (January..December) %m Month, numeric (00..12) %p AM or PM %r Time, 12-hour (hh:mm:ss followed by AM or PM) %S Seconds (00..59) %s Seconds (00..59) %T Time, 24-hour (hh:mm:ss) %U Week (00..53), where Sunday is the first day of the week; WEEK() mode 0 %u Week (00..53), where Monday is the first day of the week; WEEK() mode 1 %V Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X %v Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x %W Weekday name (Sunday..Saturday) %w Day of the week (0=Sunday..6=Saturday) %X Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V %x Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v %Y Year, numeric, four digits %y Year, numeric (two digits) %% A literal % character %x x, for any “x” not listed above
自定义函数
创建自定义函数 delimiter \ # 更改换行符 create function f1( # create function是固定格式,f1是函数名 i1 int, # i1是参数,int是参数类型 i2 int) # i2是参数,int是参数类型 returns int # 设定返回值的数据类型,这个操作叫强定义 BEGIN declare num int; # 声明一个变量名,并且声明这个变量名的类型 set num = i1 + i2; # 设定函数要操作的具体内容,这里操作具体内容不能用mysql本身有的东西,比如select return(num); # 返回一个数据 END \ # 结束 delimiter ; # 还原换行符
删除自定义函数 drop function f1;
执行自定义函数 select f1(11,22); # 在查询中执行函数
存储过程
概念:存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。
存储过程的创建 delimiter // create procedure p1() # create procedure 是固定格式 p1()是存储过程 BEGIN # 设定开始标识 select * from t1; # 存储过程需要执行的SQL语句 END// # 设定结束标识 delimiter ; call p1() # 执行p1这个存储过程 存储过程的相关参数 in 仅用于传入参数用 out 仅用于返回值用 inout 既可以传入又可以当作返回值
所有参数的存储过程实例 delimiter \ create procedure p1( 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 ; set @t1 =4; # @变量名是用来创建mysql会话级的变量 set @t2 = 0; CALL p1 (1, 2 ,@t1, @t2); SELECT @t1,@t2; # 这里@变量名也是用来调用会话级的变量
事物
事物用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。事物需要借助存储过程来进行完成
事物的执行性能并不高
示例
delimiter \ create PROCEDURE p1( OUT p_return_code tinyint # 定义一个存储过程,并且让这个存储过程返回一个值,以便程序调用 ) BEGIN DECLARE exit handler for sqlexception # 如果监测到事物执行异常,则执行下面的两个代码 BEGIN -- ERROR set p_return_code = 1; # 设置p_return_code的返回值是1 rollback; # 事物回滚 END; DECLARE exit handler for sqlwarning # 如果事物执行成功一部分,则执行下面的内容 BEGIN -- WARNING set p_return_code = 2; # 设置p_return_code的返回值是2 rollback; # 回滚 END; START TRANSACTION; # 开始执行事物 DELETE from tb1; # 事物内容第一行 insert into tb2(name)values('seven'); # 事物内容第二行 COMMIT; # 提交 -- SUCCESS set p_return_code = 0; # 如果上面的事物执行成功,则设置p_return_code的返回值0 END\ delimiter ;
动态执行SQL(防SQL注入)
BEGIN #Routine body goes here... /*SQL语句变量*/ DECLARE vstrSql VARCHAR(3000) DEFAULT ''; /*映射表字段*/ DECLARE vSourceTableName VARCHAR(50); DECLARE vSourceIdFieldName VARCHAR(50); DECLARE vSourceNameFieldName VARCHAR(50); DECLARE vTargetTableName VARCHAR(50); DECLARE vTargetIdFieldName VARCHAR(50); DECLARE vTargetNameFieldName VARCHAR(50); /*更新数据*/ DECLARE vnewValue VARCHAR(100); DECLARE vSourceIdFieldValue VARCHAR(100); DECLARE Done INT DEFAULT 0; /*声明游标*/ DECLARE curRow CURSOR FOR SELECT SourceTableName,SourceIdFieldName,SourceNameFieldName,TargetTableName,TargetIdFieldName,TargetNameFieldName FROM db_redundancy.TableFieldMap; /*设置终止标记*/ DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET Done = 1; /*打开游标*/ OPEN curRow; /*循环取出数据*/ FETCH NEXT FROM curRow INTO vSourceTableName,vSourceIdFieldName,vSourceNameFieldName,vTargetTableName,vTargetIdFieldName,vTargetNameFieldName; WHILE Done<>1 DO #获取需要更新的数据 SELECT SourceNameFieldNewValue,SourceIdFieldValue INTO vnewValue,vSourceIdFieldValue FROM db_redundancy.TableFieldValueModifyLog WHERE IsProcess=0 AND SourceTableName=vSourceTableName AND SourceIdFieldName=vSourceIdFieldName AND SourceNameFieldName=vSourceNameFieldName ORDER BY CreateDate DESC limit 1; IF ISNULL(vnewValue) <> NULL || LENGTH(trim(vnewValue))>1 THEN #拼接语句 SET vstrSql=CONCAT(' UPDATE ',vTargetTableName,' SET ', vTargetNameFieldName ,' = "',vnewValue,'" WHERE ', vTargetIdFieldName ,' = ', vSourceIdFieldValue,';'); #注意很重要,将连成成的字符串赋值给一个变量(可以之前没有定义,但要以@开头) SET @vSql= vstrSql; #预处理需要执行的动态SQL,其中stmt是一个变量 PREPARE stmt FROM @vSql; #执行语句 EXECUTE stmt ; #释放语句 DEALLOCATE PREPARE stmt; #更新历史表中状态标记 UPDATE db_redundancy.TableFieldValueModifyLog SET IsProcess=1 WHERE IsProcess=0 AND SourceTableName=vSourceTableName AND SourceIdFieldName=vSourceIdFieldName AND SourceIdFieldValue=vSourceIdFieldValue; END IF; #重置数据 SET vnewValue=''; SET vstrSql=''; FETCH NEXT FROM curRow INTO vSourceTableName,vSourceIdFieldName,vSourceNameFieldName,vTargetTableName,vTargetIdFieldName,vTargetNameFieldName; END WHILE; /*关闭游标*/ CLOSE curRow; END
注意:防SQL注入可以在程序级别操作,也可以在SQL语句中做限制
索引
索引是一种数据加速查找的结构文件,需要使用者通过相关的SQL语句进行创建
加速查找及部分约束
主键索引:加速查找,且内容不能为空、不能重复
普通索引:加速查找
唯一索引:加速查找,且不能重复
组合索引:多列组合成一个索引,功能可以参考上面的索引内容,组合的方式有如下几种
组合主键索引
组合唯一索引
组合普通索引
hash索引与btree索引,默认使用btree索引
查询快、插入/更新慢、加速查找需要命中索引内容才可以
组合索引:特点是最左前缀匹配,组合索引效率大于索引合并
覆盖索引:在索引文件中直接获取数据,这种方式其实也没有多少加速效果
索引合并:把多个单列索引合并使用,特点是方便一个表中有多列需要加速,不足是联合索引速度不如组合索引
数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。即使建立索引,索引也不会生效,索引的命中规则如下: - like '%xx'(尽量不要用like匹配) select * from tb1 where name like '%cn'; - 使用函数(不要用函数) select * from tb1 where reverse(name) = 'wupeiqi'; - or select * from tb1 where nid = 1 or email = 'seven@live.com'; 特别的:当or条件中有未建立索引的列才失效,以下会走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex' - 类型不一致 如果列是字符串类型,传入条件是必须用引号引起来,不然... select * from tb1 where name = 999; - != select * from tb1 where name != 'alex' 特别的:如果是主键,则还是会走索引 select * from tb1 where nid != 123 - > select * from tb1 where name > 'alex' 特别的:如果是主键或索引是整数类型,则还是会走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 - order by select email from tb1 order by name desc; 当根据索引排序时候,选择的映射如果不是索引,则不走索引 特别的:如果对主键排序,则还是走索引: select * from tb1 order by nid desc; - 组合索引最左前缀 如果组合索引为:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引 注意事项: - 避免使用select * - count(1)或count(列) 代替 count(*) - 创建表时尽量时 char 代替 varchar - 表的字段顺序固定长度的字段优先 - 组合索引代替多个单列索引(经常使用多个条件查询时) - 尽量使用短索引 - 使用连接(JOIN)来代替子查询(Sub-Queries) - 连表时注意条件类型需一致 - 索引散列值(重复少)不适合建索引,例:性别不适合
# 作用:加速查询 # 单独创建:create index index_name on table_name(column_name) # 删除格式:drop index_name on table_name; # 查看索引:show index from table_name; # 连表创建: create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, index ix_name (name) ) 注意:对于创建索引时如果是BLOB 和 TEXT 类型,必须指定length。
# 作用:加速查询 和 唯一约束(可含null) # 单独格式:create unique index 索引名 on 表名(列名) # 删除格式:drop unique index 索引名 on 表名 # 连表创建: create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, unique ix_name (name) )
# 作用:加速查询 和 唯一约束(不可含null) # 定义格式:alter table 表名 add primary key(列名); # 删除格式1:alter table 表名 drop primary key; # 删除格式2:alter table 表名 modify 列名 int, drop primary key; # 创建表 + 创建主键 create table in1( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text, index ix_name (name) ) 或者 create table in1( nid int not null auto_increment, name varchar(32) not null, email varchar(64) not null, extra text, primary key(ni1), index ix_name (name) )
# 作用:将n个列组合成一个索引 # 应用场景:频繁的同时使用n列来进行查询,如:where n1 = 'alex' and n2 = 666。 # 创建表 create table in3( nid int not null auto_increment primary key, name varchar(32) not null, email varchar(64) not null, extra text ) # 创建组合索引 create index ix_name_email on in3(name,email); 注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并。 # 如上创建组合索引之后,查询: name and email -- 使用索引 name -- 使用索引 email -- 不使用索引