MySQ存储过程,函数和视图

一,存储过程 PROCEDURE

存储过程是什么?其实存储过程很简单,无非就是按照其特定的语法,创建存储过程,然后在执行程序的时候,调用就行了。比如我们批量插入大量数据,就可以写一个存储过程来执行,类似于脚本的功能。
怎么调用呢?下面是一个创建存储过程的实例

关键字 PROCEDURE 例如:

CREATE PROCEDURE demo() /定义存储过程名称
  BEGIN
   SELECT COUNT(*) FROM test/表名;
  END
//执行存储过程
CALL demo ; 

优缺点

优点

  • 存储过程在创建的时候直接编译,而sql语句每次使用都要编译,提高执行效率
  • 一个存储过程可以被重复使用。
  • 一条sql语句,可能需要访问几张表,对数据库连接好几次,存储过程只会连接一次
  • 存储的程序是安全的。数据库管理员可以向访问数据库中存储过程的应用程序授予适当的权限,而不向基础数据库表提供任何权限。(主要优点吧)

缺点

  1. 可移植性太差
  2. 对于简单的sql语句,毫无意义
  3. 对于只有一类用户的系统安全性毫无意义
  4. 团队开发,标准不设定好,后期维护很麻烦
  5. 对于开发和调试都很不方便。
  6. 复杂的业务逻辑,用存储过程还是很吃力

基本上面的有点都是性能更快,但服务器也不会因为这一点性能而变得很慢,所以基本用存储过程的很少,一般情况下,不建议使用,比较麻烦,除非有特定需求。

实例:
show procedure status //查看存储过程状态
show create procedure demo \G // 查看详细,也可以用来查看表和数据库
show 语句后面跟一个 \G 用于格式化语句 ,显示出这种格式

否则 就是一长串数据 ,就像乱码一样。

delimiter // 
create procedure demo(out s int)
begin
select count(*) into s from mysql.user;
end
//
delimiter;
这里先解释一下delimiter //是什么意思
mysql客户端.中分隔符默认是分号(;),所以如果不指定一个特殊的分隔符,可能会编译失败
上面语句将分隔符改为//,直到遇到下一个//才表示语句结束,这样可以保证创建语句完整。

上面的select count(*) into s from mysql.user;语句中 into s的意思对应out s int,表示声明输出值为一个int类型的值 , 其实不声明上面的输出值也是没问题的

delimiter // 
create procedure demo()
begin
select count(*)from testfield.test_obe_event;
end
//
delimiter;

带输入输出参数的存储过程

输入:
drop procedure if exists demo //
create procedure demo(in p int)
comment 'insert into a int value'
begin
/* 将输入参数的值赋给变量 */
set @v1 = p;(这里只是学习一种变量声明方式,直接在v1前面加@,表示声明变量,也可以用declare v1 int声明)
insert into test(id) values(v1);
end
//
/* 调用这个存储过程 */
call demo(1)//
/* 去数据库查看调用之后的结果 */
select * from test//
输出:
drop procedure if exists demo//
create procedure demo(out p int)
begin
select max(id) into p from test;
end
//
call demo(@pv)//(调用该存储过程,注意:输出参数必须是一个带@符号的变量)

/* 查询刚刚在存储过程中使用到的变量 */
select @pv//
同时具备输入输出:
drop procedure if exists demo//
create procedure demo(in p1 int , out p2 int)
begin
if p1 = 1 then
set @v = 10;(直接在v1前面加@,表示声明变量,也可以用declare v1 int声明)
else
set @v = 20;
end if;
/* 语句体内可以执行多条sql,但必须以分号分隔 */
insert into test(id) values(@v);
select max(id) into p2 from test;
end
//

/*调用该存储过程,注意:输出参数必须是一个带@符号的变量*/
call demo(1,@ret)//   
select @ret//
又当输入又当输出:
drop procedure if exists demo//
create procedure demo(inout p4 int)
begin
if p4 = 4 then
set @pg = 400;
else
set @pg = 500;
end if; 
select @pg;
end//
call demo(@pp)//
/* 这里需要先设置一个已赋值的变量,然后再作为参数传入 */
set @pp = 4//
call demo(@pp)//

二,函数 FUNCTION

其实存储过程也可以理解为特殊的函数。

 定义

MySQL中,创建存储函数的基本形式如下:
CREATE FUNCTION sp_name([func_parameter[,...]]) 
RETURNS type 
[characteristic ...] routine_body 
Return

子句用于声明存储函数返回值的数据类型。存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。
调用存储函数

Select sp_name([func_parameter…]) 
Select fn_search(2);

删除存储函数drop
修改存储函数alter 修改存储函数的某些相关特征。

函数使用例子 (比较大小 ,返回大的数)

CREATE FUNCTION sp_cal_max(p_num1 INT,p_num2 INT) 
RETURNS INT
BEGIN
IF p_num1 >= p_num2 THEN
RETURN p_num1; 
ELSE
RETURN p_num2; 
END IF; 
END

调用:
SET @p_num1=2; 
SET @p_num2=34; 
SELECT sp_cal_max(@p_num1,@p_num2);

存储过程和函数区别

1)一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数不能用于执行一组修改全局数据库状态的操作。

2)对于存储过程来说可以返回参数,如记录集,而函数只能返回值或者表对象。函数只能返回一个变量;而存储过程可以返回多个。存储过程的参数可以有IN,OUT,INOUT三种类型,而函数只能有IN类~~存储过程声明时不需要返回类型,而函数声明时需要描述返回类型,且函数体中必须包含一个有效的RETURN语句。

3)存储过程,可以使用非确定函数,不允许在用户定义函数主体中内置非确定函数。

4)存储过程一般是作为一个独立的部分来执行( EXECUTE 语句执行),而函数可以作为查询语句的一个部分来调用(SELECT调用),由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。 SQL语句中不可用存储过程,而可以使用函数。

三,视图 view

啥是视图?
顾名思义,视图就是用来看的图,数据库中可以理解为表,即用来看的表。
视图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。作为一个select语句保存在数据字典中的。

通过视图,可以展现基表的部分数据;视图数据来自定义视图的查询中使用的表,使用视图动态生成。 (基表:用来创建视图的表叫做基表base table )

优点:

  • 简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。
  • 安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。
  • 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

总之,使用视图的大部分情况是为了保障数据安全性,提高查询效率。

创建视图:

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    VIEW view_name [(column_list)]
    AS select_statement
   [WITH [CASCADED | LOCAL] CHECK OPTION]

解析:

  • OR REPLACE:表示替换已有视图
  • ALGORITHM:表示视图选择算法,默认算法是UNDEFINED(未定义的):MySQL自动选择要使用的算法 ;merge合并;temptable临时表
  • select_statement:表示select语句
  • [WITH [CASCADED | LOCAL] CHECK OPTION]:表示视图在更新时保证在视图的权限范围之内
  • cascade是默认值,表示更新视图的时候,要满足视图和表的相关条件
  • local表示更新视图的时候,要满足该视图定义的一个条件即可
  • TIPS:推荐使用WHIT [CASCADED|LOCAL] CHECK OPTION选项,可以保证数据的安全性
基本格式:
  create view <视图名称>[(column_list)]
       as select语句
       with check option;

单表视图创建:(自己先准备数据)

mysql> create view demo(编号,名字,性别,电话)
    -> as
    -> select PLAYERNO,NAME,SEX,PHONENO from PLAYERS
    -> where SEX='F'
    -> with check option;
Query OK, 0 rows affected (0.00 sec)
mysql> desc demo;
+--------+----------+------+-----+---------+-------+
| Field  | Type     | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+-------+
| 编号    | int(11)  | NO   |     | NULL    |       |
| 名字    | char(15) | NO   |     | NULL    |       |
| 性别    | char(1)  | NO   |     | NULL    |       |
| 电话    | char(13) | YES  |     | NULL    |       |
+--------+----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> select * from  demo;
+--------+-----------+--------+------------+
| 编号    | 名字      | 性别    | 电话        |
+--------+-----------+--------+------------+
|      8 | Newcastle | F      | 070-458458 |
|     27 | Collins   | F      | 079-234857 |
|     28 | Collins   | F      | 010-659599 |
|    104 | Moorman   | F      | 079-987571 |
|    112 | Bailey    | F      | 010-548745 |
+--------+-----------+--------+------------+
5 rows in set (0.02 sec)

多表视图创建:

mysql> create view demo3
    -> as 
    -> select a.PLAYERNO,a.NAME,MATCHNO,WON,LOST,c.TEAMNO,c.DIVISION
    -> from 
    -> PLAYERS a,MATCHES b,TEAMS c
    -> where a.PLAYERNO=b.PLAYERNO and b.TEAMNO=c.TEAMNO;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from demo3;
+----------+-----------+---------+-----+------+--------+----------+
| PLAYERNO | NAME      | MATCHNO | WON | LOST | TEAMNO | DIVISION |
+----------+-----------+---------+-----+------+--------+----------+
|        6 | Parmenter |       1 |   3 |    1 |      1 | first    |
|       44 | Baker     |       4 |   3 |    2 |      1 | first    |
|       83 | Hope      |       5 |   0 |    3 |      1 | first    |
|      112 | Bailey    |      12 |   1 |    3 |      2 | second   |
|        8 | Newcastle |      13 |   0 |    3 |      2 | second   |
+----------+-----------+---------+-----+------+--------+----------+
5 rows in set (0.04 sec)
  • 视图将我们不需要的数据过滤掉,将相关的列名用可以用自定义的列名替换。视图只是作为一个访问接口。
  • 如果创建视图时不明确指定视图的列名,那么列名就和定义视图的select子句中的列名完全相同;
  • 如果显式的指定视图的列名就按照指定的列名。
  • 注意:显示指定视图列名,要求视图名后面的列的数量必须匹配select子句中的列的数量。
  • show create view语句查看视图信息
  • 视图一旦创建完毕,就可以像一个普通表那样使用,视图主要用来查询 mysql> select * from view_name;
  • 有关视图的信息记录在information_schema数据库中的views表中

视图的更改
通常我们将视图只是用来查看数据,但是对视图的修改也会影响基表同步修改数据

CREATE OR REPLACE VIEW语句修改视图
create or replace view view_name as select语句;

ALTER语句修改视图

ALTER
    [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
    [DEFINER = { user | CURRENT_USER }]
    [SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

注意:修改视图是指修改数据库中已存在的表的定义,当基表的某些字段发生改变时,可以通过修改视图来保持视图和基本表之间一致

DML操作更新视图

因为视图本身没有数据,因此对视图进行的dml操作最终都体现在基表中

mysql> create view demo as select * from student;
mysql> select * from demo;
+--------+--------+------+
| 学号    | name   | sex  |
+--------+--------+------+
|      1 | 张三    | M    |
|      2 | 李四    | F    |
|      5 | 王五    | NULL |
+--------+--------+------+
mysql> update demo set name='钱六' where 学号='1';
mysql> select * from student;
+--------+--------+------+
| 学号    | name   | sex  |
+--------+--------+------+
|      1 | 钱六    | M    |
|      2 | 李四    | F    |
|      5 | 王五    | NULL |
+--------+--------+------+

视图的DML操作不是任何视图都可以做DML操作。有下列内容之一,视图不能做DML操作:

    ①select子句中包含distinct
  ②select子句中包含组函数
  ③select语句中包含group by子句
  ④select语句中包含order by子句
  ⑤select语句中包含union 、union all等集合运算符
  ⑥where子句中包含相关子查询
  ⑦from子句中包含多个表
  ⑧如果视图中有计算列,则不能更新
  ⑨如果基表中有某个具有非空约束的列未出现在视图定义中,则不能做insert操作

drop删除视图 :
删除视图是指删除数据库中已存在的视图,删除视图时,只能删除视图的定义,不会删除数据,也就是说不动基表:

DROP VIEW [IF EXISTS]   
view_name [, view_name] ...
mysql> drop view v_student; 

使用WITH CHECK OPTION约束: 

对于可以执行DML操作的视图,定义时可以带上WITH CHECK OPTION约束
作用:对视图所做的DML操作的结果,不能违反视图的WHERE条件的限制。

例如:

mysql> create view demo
    -> as
    -> select * from PLAYERS
    -> where birth_date < '1960-01-01'
    -> with check option;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from demo;
+----------+---------+----------+------------+-----+--------+---------------
| PLAYERNO | NAME    | INITIALS | BIRTH_DATE | SEX | JOINED | STREET        
+----------+---------+----------+------------+-----+--------+---------------
|        2 | Everett | R        | 1948-09-01 | M   |   1975 | Stoney Road    | 
|       39 | Bishop  | D        | 1956-10-29 | M   |   1980 | Eaton Square   | 
|       83 | Hope    | PK       | 1956-11-11 | M   |   1982 | Magdalene Road | 
+----------+---------+----------+------------+-----+--------+---------------
3 rows in set (0.02 sec)

此时,使用update对视图进行修改:
mysql> update demo
    -> set BIRTH_DATE='1970-09-01'
    -> where PLAYERNO=39;
ERROR 1369 (HY000): CHECK OPTION failed 'TENNIS.demo'

因为违反了视图中的WHERE birth_date < '1960-01-01'子句,所以抛出异常;
利用with check option约束限制,保证更新视图是在该视图的权限范围之内。

嵌套视图:定义在另一个视图的上面的视图

mysql> create view demo
    -> as
    -> select * from demo2
   -> where JOINED < 1980;
  • 使用WITH CHECK OPTION约束时,(不指定选项则默认是CASCADED)
  • 可以使用CASCADED或者 LOCAL选项指定检查的程度:
  • WITH CASCADED CHECK OPTION:检查所有的视图例如:嵌套视图及其底层的视图
  • WITH LOCAL CHECK OPTION:只检查将要更新的视图本身
  • 对嵌套视图不检查其底层的视图 

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据