您的位置:首页 > 数据库 > MySQL

MySql视图、存储过程和触发器

2017-12-04 23:12 555 查看
一、视图

1、定义:由查询结果形成的一张虚拟表,是表通过某种运算得到的一个投影。

创建视图的语法:create view view_name as select 语句

说明:

(1)视图名和表名是一个级别的名字,隶属于数据库;

(2)该语句的含义可以理解为:就是将该select命名为该名字(视图名);

(3)视图也可以设定自己的字段名,而不是select语句本身的字段名--通常不设置。

(4)视图的使用,基础和表一样。

2、视图的作用

(1)可以简化查询

案例一:查询平均价格前3高的栏目:

传统的Sql语句写法:

# select cat_id,avg(shop_price) as pj from tbl_goods group by cat_id order by pj desc limit 3;

创建一个视图:

# create view tbl_goods_pj as cat_id,avg(shop_price) as pj from tbl_goods group by cat_id;

# select * from tbl_goods_pj order by pj desc limit 3;

案例二:查询出商品表,以及所在的栏目名称:

传统的Sql语句写法:

# select goods_id,goods_name,b.cat_name from tbl_goods a left join tbl_category b on a.cat_id=b.cat_id;

创建一个视图,简化查询:

# create view tbl_goods_catname as select goods_id,goods_name,b.cat_name from tbl_goods a left join tbl_category b on a.cat_id=b.cat_id;

# select * from tbl_goods_catname;

(2)可以进行权限控制:

把表的权限封闭,但是开放相应的视图权限,视图里只开放部分数据,比如某张表,用户表为例,2个网站搞合作,可以查询对方网站的用户,需要向对方开放用户表的权限,但是又不想开放用户表的密码字段。

再比如一个goods表,两个网站搞合作,可以相互查询对方的商品表,比如进货价格字段不能让对方查看。

案例:

1、创建一个商品goods表:

create table if not exists `tbl_goods`(

    id int(11) not null primary key auto_increment,

    goods_name varchar(32) not null,

    in_price decimal(9,2) not null default 0,

    shop_price decimal(9,2) not null default 0,

    goods_number int(11) not null default 20

)engine=myisam  default charset utf8;

2、创建一个视图:

# create view tbl_goods_v1 as select id,goods_name,shop_price,goods_number from tbl_goods;

3、授权一个账号,给tbl_goods_v1视图的权限:

# grant select on test.tbl_good_v1 to 'xiongda'@'%'  identified by '123456';

4、案例测试:

<?php

$conn = mysql_connect('localhost','xiongda','123456');

mysql_query('use test');

mysql_query('set names utf8');

$res = mysql_query("select * from tbl_goods_v1");

$data = array();

while($row = mysql_fetch_assoc($res)){

    $data[] = $row;

}

echo '<pre>';

print_r($data);

3、查询视图

语法:select * from 视图名 【where 条件】

视图和表一样,可以添加where条件。

4、修改视图

语法: alter view view_name as select xxxx;

5、删除视图

语法:drop view 视图名称

6、查看视图结构

语法:desc view_name

7、查看所有视图

语法:show tables;

8、视图与表的关系

(1)视图是表的查询结果,自然表的数据改变了,影响视图的结果。

(2)如果向视图里面添加数据,如果视图的数据与表的数据一一对应时,可以修改视图里面的数据。如果不是一一对应的关系,不能修改。

(3)对于视图insert还应注意,视图必须包含表中没有默认值的列。

注意:在实际的开发中,没有对视图进行增删改的需求,创建视图,就是查询的。

9、视图的算法

二、SQL编程

1、变量声明

(1)会话变量

定义形式:set @变量名 = 值;

说明:跟PHP类似,第一次给其赋值,就算定义了;它可以在编程环境和非编程环境中使用!;在使用的任何场合也都该带“@”符号。

例:

mysql> set @name = 'xiaogang';

mysql> select @name;

(2)普通变量

定义形式:declare 变量名 类型  【default  默认值】;

说明:她必须先声明(即定义),此时也可以赋值;赋值跟会话变量一样:set 变量名=值;它只能在编程环境(存储过程、函数、触发器)中使用!!!

(3)变量的赋值形式

语法1:

set 变量名 = 表达式;#此语法中的变量必须先使用declare声明,在编程环境中使用

语法2:

set @变量名=表达式;#此方式可以无需declare语法声明,而是直接赋值,类似PHP定义变量并赋值。

语法3:

select @变量名:=表达式;#此语句会给该变量赋值,同时还会作为一个select语句输出“结果集”。

例:

mysql> select @num:=23+27;

mysql> select @num;

语法4:

select 表达式 into @变量名;#此语句虽然看起来是select语句,但其实并不输出‘结果集’,而是给变量赋值。

例:

mysql> select 80+20 into @num;

mysql> select @num;

2、运算符

(1)算术运算符:+       -          *           /           %

注意:mysql没有++和--运算符

(2)关系运算符:>、>=、  <、  <=、   !=

(3)逻辑运算符:and、or、not

3、语句块包含符:begin   end 结构。

4、if判断

语法:

if 条件 then

    代码1;

elseif 条件 then

    代码2;

else

    代码3;

end if;

通过存储过程来体验if语句的结构,创建存储过程的语法如下:

crate procedure 存储过程名(参数  类型)

begin

        // 代码

end

案例:接收一个数字,如果输入1则输出春天,2夏天,3秋天,4冬天,其他数字为出错。

create procedure p1(n int)

begin

         if       n=1 then

         select    '春天'    as    '季节‘;

         elseif  n=2 then

         select    '夏天‘   as  '季节‘;

          elseif  n=3 then

          select   ‘秋天’   as  '季节';

          elseif   n=4 then

          select    '冬天‘   as  '季节';

          else

          select  '无法五天‘   as  '季节';

          end if;

end

$

如何调用创建的存储过程呢?

语法:call   存储过程的名(参数)

mysql> call   p1(4)$

注意:通常情况下,“;”表示SQL语句结束,同时向服务器提交并执行。但是存储过程中有很多SQL语句,每一句都要以句号隔开,这时候我们就需要使用其他符号来代替向服务器提交的命令。通过delimiter命令更改语句结束符。

mysql> delimiter $

5、case判断

语法:

case  变量

when   值    then    语句;

when   值     then    语句;

else     语句;

end   case;

案例:接收4个数字,如果输入1则输出春天,2夏天,3秋天,4冬天,其他数字为出错

create  procedure p2(n int)

begin

case n

    when 1  then  select '春天' as '季节';

    when 2  then  select '夏天' as '季节';

    when 3  then   select '秋天' as '季节';

    when 4  then   select '冬天' as '季节';

    else select '无法无天' as '季节';

end case;

end$

调用:

mysql> call p2(3)$

6、循环

MySQL支持的循环有loop、while、repeat循环。

(1)loop循环 

语法:

标签名:loop

leave 标签名    --退出循环

end loop;

案例:创建一个存储过程,完成计算1到n的和。

create procedure p3(n int)

begin

declare   s    int   default 0;

declare   i    int    default 1;

aa:loop

   set s = s+i;

   set i = i+1;

if  i>n then

leave aa;

end if;

end loop;

select s;

end$

调用:

mysql> call p3(100)$

(2)while循环


while 条件 do

//代码

end while;

#案例:创建一个存储过程,完成计算1到n的和。

create procedure p4(n int)

begin

declare s int default 0;

declare i int default 1;

while  i<=n  do

set s = s+i;

set i = i+1;

end while;

select s;

end$

调用:
mysql> call p4(100)$

(4)repeat循环

repeat

  //代码

until 条件 end repeat; //满足该条件,即退出循环。

案例:创建一个存储过程,完成计算1到n的和。

create procedure p5(n int)

begin

declare s int default 0;

declare i int default 1;

repeat

set s=s+i;

set i=i+1;

until i>n end repeat;

select s;

end$

调用:
mysql>call p5(200)$

三、存储过程

1、概念

存储过程(procedure)概念类似于函数,就是把一段代码封装起来,当要执行这一段代码的时候,可以通过调用该存储过程来实现。在封装的语句体里面,可以同if/else ,case,while等控制结构。

可以进行sql编程。

查看现有的存储过程。

show procedure status

注意:创建的存储过程是属于当前数据库,不能跨数据库使用存储过程;

2、存储过程的优缺点

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。

(1)存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度

(2)当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。

(3)存储过程可以重复使用,可减少数据库开发人员的工作量。

(4)安全性高,可设定只有某些用户才具有对指定存储过程的使用权。

3、创建存储过程

语法:

create procedure 存储过程名(参数1,参数2,…)

begin

//代码

end

参数的类型:

in(输入参数): 表示该形参只能接受实参的数据——这是默认值,不写就是in;

out(输出参数):表示该形参其实是用于将内部的数据“传出”到外部给实参;

inout(输入输出参数):具有上述2个功能。

 

案例1:查询一个表里面某些语句 

create procedure p6()

begin

select * from it_goods;

end$

案例2:第二个存储过程体会参数,使用参数

比如我们取出某个id的数据

create procedure p7(goods_id int)

begin

select * from it_goods where id>goods_id;

end$

说明:

(1)存储过程中,可有各种编程元素:变量,流程控制,函数调用;

(2)还可以有:增删改查等各种mysql语句;

(3)其中select(或show,或desc)会作为存储过程执行后的“结果集”返回;

(4)形参可以设定数据的“进出方向”:

(5)存储过程是属于数据库,在哪个数据库里面定义的,就在哪个数据库里面调用。

4、调用存储过程

语法:

call 存储过程名称(参数)

在php里面如何调用,

$sql="call p7(5)";

mysql_query($sql);

5、删除存储过程

语法:drop procedure
存储过程的名称

6、创建复杂的存储过程

案例1,体会“控制结构”;

定义一个存储过程,有两个参数,第一个参数是价格,第二个参数是一个字符串,

如果该字符串等于’h’ 则就取出大于该价格(第一个参数)商品数据,其他则输出小于该价格的商品;

create procedure p8(price decimal(9,2),s char(1))

begin

if s = 'h' then

select * from it_goods where shop_price>price;

else

select * from it_goods where shop_price<price;

end if;

end$

案例2:带有输出参数的存储过程

create procedure p9(in num int,out res int)

begin

set res = num*num;

end$

注意:在调用具有输出参数的存储过程时,要使用一个变量来接收。

call p9(8,@res);select @res;

案例3:带有输入输出参数的存储过程

create procedure p10(inout num int)

begin

set num=num*num;

end$

注意:在调用时先创建一个变量,调用存储过程时,使用该变量接收。

set @a = 10;call p10(@a);select @a$

7、declare声明局部变量,在编程环境里面使用

8、用户变量

用户变量只要在前面加一个@符即可

set @name=’李白’;

select @name;

9、系统变量

MySQL启动的时候就存在的变量,以@@开头的都是系统变量 

select @@version$

四、存储过程

1、自定义函数

(1)定义语法

create function 函数名(参数1  参数1的类型,.......)
returns 返回值类型

begin

//代码

end

说明:

(1)函数内部可以有各种编程语言的元素:变量,流程控制,函数调用;

(2)函数内部可以有增删改等语句!

(3)但:函数内部不可以有select(或show或desc)这种返回结果集的语句!

(2)调用

跟系统函数调用一样:任何需要数据的位置,都可以调用该函数。

案例1:返回两个数的和。

create function sumhe(num1 int,num2 int) returns int

begin

return num1+num2;

end$

案例2:定义一个函数,返回1到n的和。

create function nh3(n int) returns int

begin

declare s int default 0;

declare i int default 1;

while i<=n do

set s = s+i;

set i = i+1;

end while;

return s;

end$

注意点:创建的函数,是隶属于数据库的,只能在创建函数的数据库中使用。

(3)删除函数

语法:drop function
函数名称


# drop function sumhe$

2、系统函数

(1)数字类

mysql> select rand();//返回0到1间的随机数

mysql>select * from it_goods  order by rand() limit 2;//随机取出2件商品

mysql>select  floor(3.9)//输出3

mysql>select  ceil(3.1)//输出4

mysql>select  round(3.5)//输出4四舍五入

(2)大小写转换

mysql> select ucase('I am a boy!') //    --转成大写

mysql> select lcase('I am a boy!') //    --转成小写

(3)截取字符串

mysql> select left('abcde',3)// --从左边截取3个

mysql> select right('abcde',3) //        --从右边截取3个

mysql> select substring('abcde',2,3)//   --从第二个位置开始,截取3个,位置从1开始

mysql> select concat(10,':锄禾日当午')//  --字符串相连

mysql> select coalesce(null,123);

coalesce(str1,str2):如果第str1为null,就显示str2

mysql> select stuname,stusex,coalesce(writtenexam,'缺考'), coalesce(labexam,'缺考') from stuinfo 

mysql> select length('锄禾日当午') //   输出10   显示字节的个数

mysql> select char_length('锄禾日当午') //
输出5   显示字符的个数

mysql> select length(trim('  abc  ')) //  trim用来去字符串两边空格

mysql> select replace('abc','bc','pache')//   将bc替换成pache

(4)时间类

mysql> select unix_timestamp()   //--时间戳

mysql> select from_unixtime(unix_timestamp())//  --将时间戳转成日期格式

mysql> select  curdate();返回今天的时间日期:

mysql> select now() // --取出当前时间

案例1:比如一个电影网站,求出今天添加的电影;在添加电影时,有一个添加的时间戳。

思考:条件是什么?

select  title,from_unixtime(senddate,'%Y-%m-%d') from dede_archives where from_unixtime(senddate,'%Y-%m-%d')=curdate();

案例2:比如一个电影网站,求出昨天添加的电影;在添加电影时,有一个添加的时间戳。

select  title,from_unixtime(senddate,'%Y-%m-%d') shijian from dede_archives where from_unixtime(senddate,'%Y-%m-%d')=date_sub(curdate(),interval 1 day);

案例3:比如一个电影网站,取出8天之前,添加的电影,

select  title,from_unixtime(senddate,'%Y-%m-%d') shijian from dede_archives where from_unixtime(senddate,'%Y-%m-%d')<date_sub(curdate(),interval 8 day);

 

扩展,如何取出昨天或者指定某个时间的电影:

date_sub(负数是向后计算)

基本用法:

date_sub(时间日期时间,interval
数字  时间单位)

说明:

(1)时间单位:可以是year month day hour minute second

(2)数字:可以是正数和负数。

比如:取出昨天的日期:

mysql> select date_sub(curdate(),interval 1 day);

比如:取出上一个月日期:

mysql> select date_sub(curdate(),interval 1 month);

date_add(负数是向前计算)函数:用法;

比如:取出明天的日期:

select date_add(curdate(),interval  1  day);

五、触发器

1、简介

(1)触发器是一个特殊的存储过程,它是MySQL在insert、update、delete的时候自动执行的代码块。

(2)触发器必须定义在特定的表上。

(3)自动执行,不能直接调用,

作用:监视某种情况并触发某种操作。 

触发器的思路:

监视it_order表,如果it_order表里面有增删改的操作,则自动触发it_goods里面里面增删该的操作。

比如新添加一个订单,则it_goods表,就自东减少对应商品的库存。

比如取消一个订单,则it_goods表,就自动增加对应商品的库存减少的库存。

#创建一个订单表

create table it_order(

id int not null comment '订单的id',

goods_id int not null comment '商品的id',

much int not null comment '购买数量'

)engine myisam charset utf8;

2、触发器四要素

监视地点(table)

监视事件 (insert/update/delete)

触发时间(after/before)

触发事件(insert/update/delete)

3、创建触发器

创建触发器的语法:

create  trigger  trigger_name

after/before  insert /update/delete  on   表名

for each row

begin

sql语句:(触发的语句一句或多句)

end

案例1:购买商品,减少对应库存 

注意:如果在触发器中引用行的值。

在监视it_order表时,对于insert而言,新增的行用new来表示,行中的每一列的值,用new.列名来表示。

create  trigger  t1 

after  insert  on   it_order

for each row

begin

update it_goods set goods_number=goods_number-new.much where id=new.goods_id;

end$

测试创建的触发器;

# select * from it_goods;

比如我们购买5个鸡蛋;

# insert into it_order values(1,2,5);

案例2:取消订单时,减掉的库存要添加回来

分析:

监视的地点:it_order

监视的事件:it_order表的delete操作;

触发的时间:it_order表的delete操作后;

触发的事件:it_goods表减掉的库存,重新添加回来操作。

create  trigger  t2 

after  delete  on   it_order

for each row

begin

update it_goods set goods_number=goods_number+old.much where id=old.goods_id;

end$

测试触发器了,

撤销刚才买的5个鸡蛋

# select * from it_goods;

# delete from it_order where id=1$;

# select * from it_goods;

注意:对于delete而言,删除的行用old来表示,行中的每一列的值,用old.列名
来表示。


案例4:修改订单时,库存也要做对应修改(修改的数据,有商品的数量,类型)

分析:

监视的表是:it_order;

监视的事件:it_order表的update操作

触发的时间:it_order表的update操作之后

触发的事件:it_goods表里面修改库存,

注意:

对于update而言,修改之前行用old来表示,行中的每一列的值,用 old.列名来表示。

修改之后,用new来表示,行中的每一列的值,用 new.列名来表示

思路:如何完成修改订单,触发it_goods表的操作,

(1)取消订单

(2)重新下单

create  trigger  t3 

after   update  on   it_order

for each row

begin

update it_goods set goods_number=goods_number+old.much where id=old.goods_id;

update it_goods set goods_number=goods_number-new.much where id=new .goods_id;

end$

测试触发器

# select * from it_goods$;

# select * from it_order$;

修改订单了,改成购买20个包菜 

# update it_order set goods_id=6,much=20 where id=1;



# select * from it_goods$;

# select * from it_order$;

4、删除触发器

语法:drop trigger
触发器的名称

5、查看触发器

语法: show triggers

show triggers\G

6、before和after的区别

监视的事件触发后执行,还是触发前执行。

after是先完成数据的增删改(it_order),再触发,触发器中的语句晚于监视的增删改,无法影响前面的增删该动作。

就类似于先吃饭,再付钱。

before是先完成触发,再增删改,触发的语句先于监视的增删改发生,我们有机会判断修改即将发生的操作。

就类似于先付钱,再吃饭

典型案例:对于已下的订单,进行判断,如果订单的数量>5,就认为是恶意订单,强制把所定的商品数量改成5

分析:

监视的表 :it_order

监视的事件:it_order表的insert操作

触发的时间:it_order表的insert操作之前

触发的事件:如果订单数量大于5,则改成5

create  trigger  t4

before   insert  on  it_order

for each row

begin

if new.much>5 then

set new.much=5;

end if;

end$

测试案例:
# select * from it_goods;

# select * from it_orders;

# insert into it_order values (3,4,10);

# select * from it_goods;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: