视图是一个虚拟表
视图根据基表创建
包含字段,数据源于对应的真实表(基表)
CREATE VIEW <视图名> AS <SELECT语句>; -- 创建视图语法,使用 select 语句中获取的数据显示在视图中
create view view_name as select 语句; -- 创建视图
alter view view_name as select 语句; -- 修改视图
show create view view_name; -- 显示视图创建指令
drop view view_name1,view_name2; -- 删除(多个)视图
-- 创建视图user_view, 只能查看 user 表中的 name、id、age 字段
create view user_view
as select name, id, age from user
select name, id, age from user_view; -- 从视图表 user_view 中查询数据
show create view user_view; -- 查看创建视图 user_view 的指令
alter view user_view
as select id,name from user; -- 修改视图 user_view: 在视图中只显示 id 和 name 字段数据
drop view user_view; -- 删除视图
视图创建后在磁盘中只有结构文件,没有数据文件
视图的建立和删除只影响视图本身,不影响对应的基本表
视图可以嵌套,即从其他视图中检索数据的查询来创建视图
创建视图需要足够的访问权限
创建视图的数目没有限制
视图不能索引,也不能有关联的触发器、默认值或规则
视图可以和表一起使用
MySQL
实现的存储过程略有不同:按需编译MySQL
将其放入缓存,为每个连接维护自己的存储过程高速缓存# 创建简单存储过程
delimiter $$ -- 修改语句结束符
create procedure 存储过程名(参数类型 参数名 参数数据类型)
begin -- 开始语句
-- 过程主体部分,若只有一条 SQL 语句,可省略 BEGIN-END 标志
end && -- 结束语句
delimiter ; -- 恢复语句结束符
# 调用存储过程
call 存储过程名(参数)
# 删除存储过程
drop procedure [ IF EXISTS ] 存储过程名称;
# 查看存储过程
SHOW PROCEDURE STATUS LIKE '存储过程名';
# 查看指定数据库中的存储过程
select name from mysql.proc where db='数据库名';
select routine_name from information_schema.routines where routine_schema='数据库名';
show procedure status where db='数据库名';
# 查看指定存储过程定义
SHOW CREATE PROCEDURE [数据库.]存储过程名;
# 修改存储过程
ALTER PROCEDURE 存储过程名 [ 特征 ... ];
特征
:指定存储过程的特性,可能取值有:
CONTAINS SQL
:表示子程序包含 SQL 语句,但不包含读或写数据的语句NO SQL
:表示子程序中不包含 SQL 语句READS SQL DATA
:表示子程序中包含读数据的语句MODIFIES SQL DATA
:表示子程序中包含写数据的语句SQL SECURITY { DEFINER |INVOKER }
:指明谁有权限来执行
DEFINER
:表示只有定义者自己才能够执行INVOKER
:表示调用者可以执行COMMENT 'string'
:表示注释信息ALTER PROCEDURE
语句修改存储过程的某些特征
# 创建简单存储过程
delimiter $$ -- 修改标准语句分隔符为 &&
create procedure Demo() -- 没有参数也必须有 ()
begin -- 开始单个语句,直到 && 结束
-- 主体部分,SQL 语句处理业务逻辑
end $$ -- 结束语句,可以有多个语句
delimiter; -- 恢复分隔符
# 调用存储过程
call Demo();
# 删除存储过程
drop procedure if exists Demo;
# 查看存储过程
show procedure status like 'Demo';
# 查看指定数据库中的存储过程
select name from mysql.proc where db='demo';
select routine_name from information_schema.routines where routine_schema='demo';
show procedure status where db='demo';
# 查看指定存储过程定义
SHOW CREATE PROCEDURE demo.Demo;
# 修改存储过程特征:将读写权限改为 MODIFIES SQL DATA,并指明调用者可以执行
ALTER PROCEDURE Demo MODIFIES SQL DATA SQL SECURITY INVOKER;
参数类型:IN
、OUT
、INOUT
create procedure 名称([IN|OUT|INOUT] 参数名 参数数据类型 )
begin ......... end
输入参数;一般只用于传入,在调用过程中一般不作为修改和返回
表示调用者向过程传入值,可以是字面量或变量
不显示指定参数类型默认是 in
类型
delimiter $$
create procedure Demo(in num2 int) -- 没有参数也必须有 ()
begin
select num2; -- 显示 null
set num2 = 7; -- 参数赋值
select num2; -- 显示 7
end $$
delimiter;
# 调用存储过程
call Demo(@num2); -- 显示 null,第一个查询
call Demo(5); -- 显示 5,第一个查询
select @num2; -- null,未赋值
输出参数;调用存储过程中,可改变其值并返回
out
参数也需要指定,但必须是变量,不能是常量delimiter $$
create procedure Demo2(out num int) -- 没有参数也必须有 ()
begin
set num = 6; -- 设置变量 num,修改变量值为 6
select num; -- 返回变量
end $$
delimiter;
# 调用存储过程
call Demo2(@num); -- 结果为 null
select @num -- 变量值 @num = 6
输入输出参数
建议
in
参数,返回值使用out
参数
inout
参数就尽量的少用变量具有数据类型和长度
mysql
的SQL数据类型保持一致通过 set
赋值变量
SET
语句可同时为多个变量赋值,各变量的赋值语句之间用逗号隔开
或通过 select ... into ...
方式赋值
SELECT col_name [...] INTO var_name[,...]
FROM table_name WEHRE condition
将查询结果赋值给变量时,该查询语句的返回结果只能是单行
使用 select
语句返回变量
select 变量名;
declare
声明变量
declare
只声明一个变量局部变量必须先声明后使用
BEGIN ... END
复合语句中,且必须在开头任何其它语句之前可用在嵌套的块中,相同名字声明变量的块除外
DEFAULT
子句设值默认值
MySQL不支持数组作为局部变量
delimiter $$
create procedure demo(out num1 int) -- 输出参数
begin
declare num2 int default(select count(*) from PLAYERS); -- 定义局部变量,默认值为 sql 语句结果
set num1 = num2; -- 赋值
end $$
delimiter ;
call demo(@num); -- 调用存储过程,虽然是输出参数但必须指定
select @num; -- 查询结果
与数据库连接有关
当前连接中声明的变量,连接断开的时消失
用户变量名一般以 @
开头
@var_name
,有 @
符号赋值
set
语句
可使用 =
或 :=
作为分配符
变量可为整数、实数、字符串或者NULL值
select
语句
:=
,不能用 =
=
被视比较操作符set @a = 1; -- 定义用户变量 @a,值为 1
select @a; -- 查询变量 @a
select @b := 2; -- 定义用户变量 @b,值为 2,并查询
select @b; -- 查询变量 @
区别局部变量
局部变量只有变量名字,没有 @
符号
@
符号都是先定义,再使用
select
值为 null
局部变量只在存储过程内部使用,在过程体外没有意义
begin-end
块处理完后,局部变量消失
用户变量可以用在存储过程的内部和外部
在存储过程内部,使用局部变量,不要使用用户变量
根据系统变量的作用域分为:全局变量 、会话变量
通过 @@
或 global
操作系统变量
mysql> SET GLOBAL sort_buffer_size=value;
mysql> SET @@global.sort_buffer_size=value;
MySQL
变量类似于动态语言,变量值随所要赋的值的类型而改变
全局变量:@@global
MySQL
启动时由服务器自动将全局变量初始化为默认值
默认值可通过更改配置文件 my.ini
、my.cnf
修改
会话变量:@@session
MySQL
初始化set
系统变量时,不带作用域修饰默认指会话作用域
和存储过程一样,都是在数据库中定义一些 SQL 语句的集合
存储函数可以通过 return 语句返回函数值,主要用于计算并返回一个值
CREATE FUNCTION
语句创建存储函数
CREATE FUNCTION 函数名称 ([func_parameter [, ...]])
RETURNS type
[characteristic ...]
routine_body
func_parameter
:函数的参数列表
[IN | OUT | INOUT] param_name type;
RETURNS type
:指定返回值的类型
RETURN
语句返回类型不同于函数指定类型的值,返回值将被强制为恰当的类型ENUM
或 SET
值,但 RETURN
语句返回整数
SET
成员集的相应 ENUM
成员,从函数返回的值是字符串characteristic
参数:指定存储函数的特性
routine_body
参数:表示 SQL 代码的内容
BEGIN...END
来标示 SQL 代码的开始和结束创建函数时函数名不允许重复
function_xxx
或 func_xxx
查询
# 查询函数
SHOW FUNCTION STATUS LIKE 存储函数名;
SHOW CREATE FUNCTION 存储函数名;
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME = 存储函数名;
# 修改函数
ALTER FUNCTION 存储函数名 [ 特征 ... ]; -- 存储函数的特征与存储过程的基本一样
# 删除存储过程
DROP FUNCTION [ IF EXISTS ] <函数名>;
调用
DELIMITER $$
CREATE FUNCTION func_student(id int(11)) -- 创建存储函数
RETURNS VARCHAR(20) -- 指定返回值类型
COMMENT '查询某个学生的姓名' -- 指定注释特征
BEGIN -- 开始
RETURN(SELECT name FROM tb_student WHERE tb_student.id = id); -- 函数体,执行sql
END $$
DELIMITER ;
-- 该函数拥有一个类型为 INT(11) 的参数 id,返回值为 VARCHAR(20) 类型
-- SELECT 语句从 tb_student 表中查询 id 字段值等于所传入参数 id 值的记录,同时返回该条记录的 name 字段值
SELECT func_student(3); -- 调用自定义函数
事先定义程序执行过程中遇到的问题,定义遇到这些问题时应当采取的处理方式和解决办法
DECLARE
关键字定义条件
DECLARE 条件名称 CONDITION FOR condition_value;
sqlstate_value
:表示长度为 5 的字符串类型错误代码mysql_error_code
:表示数值类型错误代码
ERROR 1146(42S02)
中,sqlstate_value
值是 42S02,mysql_error_code
值是 1146# sqlstate_value
DECLARE can_not_find CONDITION FOR SQLSTATE '42S02';
# mysql_error_code
DECLARE can_not_find CONDITION FOR 1146;
DECLARE
关键字定义处理程序。其基本语法如下:
DECLARE handler_type HANDLER FOR condition_value[...] sp_statement
handler_type
参数:指明错误的处理方式
该参数有 3 个取值:CONTINUE
、EXIT
和 UNDO
CONTINUE
:遇到错误不进行处理,继续向下执行
EXIT
:遇到错误后马上退出
UNDO
:遇到错误后撤回之前的操作,MySQL 暂不支持
通常执行过程中遇到错误应该立刻停止执行并撤回操作
condition_value
:指明错误类型,有 6 个取值
sqlstate_value
:包含 5 个字符的字符串错误值condition_name
:表示 DECLARE 定义的错误条件名称SQLWARNING
:匹配所有以 01 开头的 sqlstate_value
值NOT FOUND
:匹配所有以 02 开头的 sqlstate_value
值SQLEXCEPTION
:匹配所有没有被 SQLWARNING
或 NOT FOUND
捕获的 sqlstate_value
值mysql_error_code
:匹配数值类型错误代码sp_statement
参数:程序语句段
# 捕获 sqlstate_value:遇到 sqlstate_value 值为 42S02,执行 CONTINUE 操作并输出 CAN NOT FIND 信息
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='CAN NOT FIND';
# 捕获 mysql_error_code:遇到 mysql_error_code 值为 1146, 执行 CONTINUE 操作并输出 CAN NOT FIND 信息
DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';
# 先定义条件,然后调用:先定义 can_not_find 条件,遇到 1146 错误就执行 CONTINUE 操作
DECLARE can_not_find CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND';
# 使用 SQLWARNING:捕获所有 01 开头的 sqlstate_value 值,然后执行 EXIT 操作并输出 ERROR 信息
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';
# 使用 NOT FOUND:捕获所有 02 开头的 sqlstate_value 值,然后执行 EXIT 操作并输出 CAN NOT FIND 信息
DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';
# 使用 SQLEXCEPTION:捕获所有没有被 SQLWARNING 或 NOT FOUND 捕获的 sqlstate_value 值,然后执行 EXIT 操作并输出 ERROR 信息
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';
MySQL 中存储过程或函数的查询有时返回多条记录
一般通过游标定位到结果集的某一行进行数据修改
结果集是符合 SQL 语句的所有记录的集合
不像多数 DBMS,MySQL 游标只能用于存储过程和函数
DECLARE
关键字声明游标,并定义相应的 SELECT 语句
根据需要添加 WHERE 和其它子句
DECLARE cursor_name CURSOR FOR select_statement;
cursor_name
:游标名称select_statement
:SELECT 语句,可以返回一行或多行数据MySQL
通过 OPEN
关键字打开游标OPEN cursor_name;
cursor_name
:所要打开游标的名称使用 FETCH...INTO
语句读取数据
FETCH cursor_name INTO var_name [,var_name]...
cursor_name
中 SELECT
语句的执行结果保存到变量参数 var_name
var_name
必须在游标使用之前定义使用游标类似高级语言中的数组遍历
MySQL
的游标是只读的
游标使用完毕后,要及时关闭
MySQL 中使用 CLOSE
关键字关闭游标
CLOSE cursor_name;
CLOSE
释放游标使用的所有内部内存和资源,因此每个游标不再需要时都应该关闭
一个游标关闭后,如果没有重新打开,则不能使用它
但使用声明过的游标不需要再次声明,用 OPEN
语句打开即可
如果不明确关闭游标,MySQL 将会在到达 END
语句时自动关闭
游标关闭后不能使用 FETCH
使用该游标
进行条件判断
if search_condition then statement_list
[elseif search_condition then statement_list] ...
[else statement_list]
end if
search_condition
:条件判断语句
end if
结束 if
语句MySQL 中的 IF( ) 函数不同于 IF 语句
进行条件判断
提供了多个条件进行选择,可实现比 IF 语句更复杂的条件判断
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list]...
[ELSE statement_list]
END CASE
case_value
:条件判断的变量,决定哪一个 WHEN 子句会被执行
when_value
:变量的取值
when_value
表达式与 case_value
变量值相同,执行对应 THEN 关键字后的 statement_list 中的语句CASE
语句都要使用 END CASE
结束
另一种形式
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
WHEN
语句将被逐个执行
search_condition
表达式为真,执行对应 THEN
关键字后的 statement_list
语句CASE
语句与 SQL CASE
表达式的 CASE
语句有轻微不同
CASE
语句不能有 ELSE NULL
语句,且用 END CASE
替代 END
终止可以使某些特定的语句重复执行
只实现了一个简单的循环,并不进行条件判断
LOOP
语句本身没有停止循环的语句,必须使用 LEAVE
语句等才能停止循环,跳出循环过程
[begin_label:] LOOP
statement_list
END LOOP [end_label]
begin_label
和 end_label
:循环开始和结束的标志
statement_list
:需要循环执行的语句
LOOP
循环都以 END LOOP
结束
例
add_num:LOOP
SET @count=@count+1;
END LOOP add_num;
-- 循环执行 count 加 1 操作,没有跳出循环的语句,循环成为死循环
用于跳出循环控制,类似 Java
的 return
LEAVE label
label
:循环的标志,LEAVE
语句必须跟在循环标志前面
例
add_num:LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num;
END LOOP add num;
-- 循环执行 count 加 1 的操作,当 count 的值等于 100 时,跳出循环
再次循环;用来跳出本次循环,直接进入下一次循环;类似 Java
的 continue
ITERATE label
label
:循环的标志,ITERATE
语句必须跟在循环标志前面
例
add_num:LOOP
SET @count=@count+1;
IF @count=100 THEN
LEAVE add_num;
ELSE IF MOD(@count,3)=0 THEN
ITERATE add_num;
SELECT * FROM employee;
END LOOP add_num;
-- 循环执行 count 加 1 操作,count 值为 100 时结束循环
-- 如果 count 的值能够整除 3,则跳出本次循环,不再执行下面的 SELECT 语句
条件控制的循环语句;类似 Java
中 do … while()
每次语句执行完毕后对条件表达式进行判断
[begin_label:] repeat
statement_list
until search_condition
end repeat [end_label]
begin_label
:为 REPEAT 语句的标注名称,可省略
REPEAT
内语句重复执行,直至 search_condition
返回值为 TRUE
REPEAT
循环都用 END REPEAT
结束
例
REPEAT
SET @count=@count+1;
UNTIL @count=100
END REPEAT;
-- 循环执行 count 加 1 的操作,count 值为 100 时结束循环
条件控制的循环语句
当满足条件时,执行循环内的语句,否则退出循环
[begin_label:]
WHILE search_condition
DO statement list
END WHILE [end label]
search_condition
:循环执行的条件,满足该条件时循环执行WHILE
循环需要使用 END WHILE
结束例
WHILE @count < 100
DO SET @count=@count+1;
END WHILE;
-- 循环执行 count 加 1 的操作,count 值小于 100 时执行循环。如果 count 值等于 100 了,则跳出循环
CALL
语句调用CALL
语句调用,也不需要手工启动
INSERT
、UPDATE
和 DELETE
操作才能激活触发器
FOREIGN KEY
约束、CHECK
约束更为复杂的检查和操作触发器使用的过程中,MySQL 按照以下方式处理错误
对于事务性表:如果触发程序失败,以及由此导致的整个语句失败,那么该语句所执行的所有更改将回滚
对于非事务性表:不能执行此类回滚,即使语句失败,失败之前所做的任何更改依然有效
若 BEFORE
触发程序失败,则 MySQL 将不执行相应行上的操作
若在 BEFORE
或 AFTER
触发程序的执行过程中出现错误,将导致调用触发程序的整个语句失败
仅当 BEFORE
触发程序和行操作均已被成功执行,MySQL 才会执行 AFTER
触发程序
INSERT
语句执行之前或之后响应的触发器
注意
NEW
(不区分大小写)的虚拟表来访问被插入的行BEFORE INSERT
触发器中,NEW
中的值也可以被更新
AUTO_INCREMENT
列,NEW
在 INSERT
执行之前包含的值是 0,在 INSERT 执行之后将包含新的自动生成值UPDATE
语句执行之前或之后响应的触发器
注意
UPDATE
触发器代码内可引用名为 NEW
(不区分大小写)的虚拟表访问更新的值UPDATE
触发器代码内可引用名为 OLD
(不区分大小写)的虚拟表访问 UPDATE
语句执行前的值
OLD
中的值全部是只读的,不能被更新BEFORE UPDATE
触发器中,NEW
中的值可能也被更新
UPDATE
语句中的值,需要具有对应的操作权限BEFORE
类型的触发器,AFTER
类型的触发器将不被允许DELETE
语句执行之前或之后响应的触发器
注意:DELETE
触发器代码内可引用名为 OLD
(不区分大小写)的虚拟表来访问被删除的行
OLD
中的值全部是只读的,不能被更新CREATE TRIGGER
语句创建触发器
CREATE TRIGGER <触发器名>
< BEFORE | AFTER > <INSERT | UPDATE | DELETE >
ON <表名>
FOR EACH Row
<触发器主体>
INSERT | UPDATE | DELETE
:触发事件,指定激活触发器的语句的种类
INSERT
:将新行插入表时激活触发器
INSERT
语句和 LOAD DATA
语句激活DELETE
: 从表中删除某一行数据时激活触发器、
DELETE
和 REPLACE
语句UPDATE
:更改表中某一行数据时激活触发器
UPDATE
语句BEFORE | AFTER
:触发器被触发的时刻,表示触发器是在激活语句之前或之后触发
BEFORE
选项AFTER
选项BEGIN…END
复合语句结构FOR EACH ROW
:一般是指行级触发
# 创建 before 类型触发器 Demo
-- 触发条件:向表 tab_name 中插入数据前对新插入的 salary 字段值进行求和计算
create trigger Demo
before insert on tab_name
for each row
set @sum = @sum + NEW.salary;
# 创建 after 类型触发器 Demo2
-- 触发条件:向表 tab_name 中插入数据后,再向表 tab_name2 插入相同数据,且 salary 为 tab_name 中插入 salary 值的 2 倍
create trigger Demo2
after insert on tab_name
for each row
insert into tab_name2 values (NEW.id, NEW.name, deptId, 2*NEW.salary);
SHOW TRIGGERS
语句查看数据库中的触发器及基本信息
SHOW TRIGGERS
命令后添加 \G
,显示信息比较有条理SHOW TRIGGERS [\G]; -- 查看当前数据库的触发器信息
Trigger
:触发器的名称Event
:激活触发器的事件Table
:激活触发器的操作对象表Statement
:触发器执行的操作Timing
:触发器触发的时间triggers
表
MySQL 中所有触发器的信息都存在 information_schema
数据库的 triggers
表中
可以通过查询命令 SELECT
查看
SELECT * FROM information_schema.triggers WHERE trigger_name= '触发器名'; -- 指定要查看的触发器的名称
SELECT * FROM information_schema.triggers \G; -- 不指定名称,查看所有触发器
修改触发器可以通过删除原触发器,再以相同的名称创建新的触发器。
使用 DROP
语句将触发器从数据库中删除
SUPER
权限DROP TRIGGER [ IF EXISTS ] [数据库名] <触发器名>
删除表的同时会自动删除该表上的触发器