3    视图  索引 存储过程与函数

3.1 视图 

视图是建立在一个或者多个表上面通过子查询建立的投影

视图本身是不包含任何数据的,视图的数据全部来自基表

基表的数据更改则视图数据更改

视图的数据修改其实是在修改基表数据

视图可以进行多视图的连接查询

 

Create view view名 (各列别名)AS 查询语句

视图如果有别名,通过别名进行列的操作

 

Drop view view名
 
Show tables;
Show create view view名
Select * from information_schema.views

 

3.2 索引 

主键索引  外键索引   全文索引    普通索引

    1. create index idx_名 ON  emp(empno,ename);
    2. alter table emp add index(empno,ename);
    3. create table emp(empno int,ename char(10),index(empno,ename));
    查看索引 show index from 表名
    删除索引 drop index index名 on 表名
    全文检索 搜索引擎为MyISAM 支持频率在50%以下的单词检索,不区分大小写
    CREATE TABLE `tt1` (
      `id` int(11) DEFAULT NULL,
      `title` text,
      `content` text,
      FULLTEXT KEY `title` (`title`,`content`)
    ) ENGINE=MyISAM DEFAULT CHARSET=gbk
     
    select * from tt1 where match(title,content) against ('mysql');

     

    3.3 存储过程与函数

    存储函数与存储过程的区别:

    存储函数不能拥有输出参数;必须添加return;

    存储函数可直接调用,且不需使用call语句,而存储过程的调用必须使用call语句;

    存储函数中必须包含一条return语句,而这条特殊的SQL语句不允许包含于存储过程。

     

    存储过程

    mysql> delimiter //
    mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
        -> BEGIN
        ->   SELECT COUNT(*) INTO param1 FROM t;
        -> END
        -> //
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> delimiter ;
    mysql> CALL simpleproc(@a);
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> SELECT @a;
    +------+
    | @a   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)

     

    函数

    mysql> delimiter //
    mysql> CREATE FUNCTION hello (s CHAR(20) charset utf8) RETURN S CHAR(50)
        -> RETURN CONCAT('Hello, ',s,'!');
        -> //
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> delimiter ;
     
    mysql> SELECT hello('world'); -- 字符串要加单引号
    +----------------+
    | hello('world') |
    +----------------+
    | Hello, world!  |
    +----------------+
    1 row in set (0.00 sec)

     

    示例:建立存储函数:根据给定的cust_id返回客户所在的州名(缩写),若库中无给定的cust_id,则返回“不存在该客户”。

     

    ->delimiter //
    ->create function fn_search(c_id int)
    ->returns varchar(50)  -- 定义返回的数据类型,与函数部分中的数据类型需统一,如函数中的“不存在该客户”为6个字符,如果这里设置为char(5),则无法输出该结果
    ->deterministic – 表示对于相同的输入值,返回值也相同
    ->begin
    ->declare state char(2); -- 声明一个变量state,作为输出的州变量
    ->select cust_state from customers where cust_id=c_id into state;
    ->if state is null then
    ->return(select ’不存在该客户’); --注意这里return不用加s
    ->else
    ->return(select state);
    ->end if;
    ->end;
    ->//
    -- 执行存储函数
    ->select fn_search(10001);
     
    显示
    mysql> SHOW  procedure status;
    mysql> SHOW  function  status;
     
    mysql> SHOW CREATE FUNCTION test.hello\G
    
    mysql> SHOW FUNCTION STATUS LIKE 'hello'\G


    练习:

    查找对应姓名雇员的奖金,如果奖金高于500,就显示‘表现优秀‘,否则继续努力’

    delimiter //
    CREATE PROCEDURE pr5(IN NAME CHAR(20) charset gbk )  
    BEGIN
    SELECT SAL,IF(SAL>50,'表现不错','继续努力') 评语,ENAME FROM  emp WHERE ENAME=NAME;
    END//
    delimiter ;
    CALL pr5('jack');
     
     
    delimiter //
    CREATE FUNCTION f7(NAME CHAR(20) charset gbk)
    RETURNS char(50) charset gbk
    BEGIN
    DECLARE result char(50) charset gbk;
    DECLARE s DOUBLE;
    SELECT emp.SAL INTO s FROM emp WHERE ename=name;
    IF s>500
    THEN SET result=CONCAT(name,' 表现不错 ,奖金',s);
    ELSE SET result=CONCAT(name,' 继续努力 ,奖金',s);
    END IF;
    RETURN result;
    END//
    delimiter ;
    SELECT f7('jack');

    3.4 触发器 

    触发器:MySQL响应insert、delete、update语句时自动执行的一条MySQL语句,创建触发器时需要给出的4条信息:唯一的触发器名、触发器相关的表、触发器应该响应的活动(insert 、delete、update)、触发器何时执行(处理前或处理后)。

    1 insert触发器:当对表插入数据时起作用,只能用after

    建立insert触发器

    SHOW CREATE TRIGGER tr2;
    DROP TRIGGER tr2;
    CREATE   TRIGGER  tr2 AFTER INSERT ON emp FOR EACH ROW
    BEGIN
    INSERT INTO emp_log VALUES (null,NOW(),'insert');
    END

    执行insert触发器

     INSERT INTO emp VALUES('0012','张三','销售','00002','2015-09-09',9000,700,'03');

    2 delete触发器:当对表删除数据时起作用,只能用after 同时返回奖金高于500的人数

    建立 delete触发器

    CREATE   TRIGGER  tr3 AFTER DELETE ON emp FOR EACH ROW
    BEGIN
    INSERT INTO emp_log VALUES (null,NOW(),'delete');
    call pro();
    END

    执行delete触发器

    delete from emp where ename=’jack’;

    3 update触发器:当对表修改数据时起作用,同时含有new和old两个虚拟表。结合New可访问更新行的记录;结合old可访问更新前行的记录,可用after,也可用before

     

    练习: 建立一个update触发器, 如果更新后的comm大于2000,则2000作为comm

    create trigger tr_u  BEFORE  update on emp for each row
    begin
    if new.comm>2000 then set new.comm=2000; end if;
    insert into emp_log values(now(),'update');
    end
     
    UPDATE emp set comm=comm*2 WHERE comm>500;
     
    SELECT * from emp;

    4 删除触发器:drop trigger trg_name;

    5 查看触发器:show triggers;

    3.5 事件

    1 事件简介

       事件(event)是MySQL在相应的时刻调用的过程式数据库对象。一个事件可调用一次,也可周期性的启动,它由一个特定的线程来管理的,也就是所谓的“事件调度器”。

       事件和触发器类似,都是在某些事情发生的时候启动。当数据库上启动一条语句的时候,触发器就启动了,而事件是根据调度事件来启动的。由于他们彼此相似,所以事件也称为临时性触发器。

       事件取代了原先只能由操作系统的计划任务来执行的工作,而且MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux下的CRON或Windows下的任务计划)只能精确到每分钟执行一次。

     

    2 事件的优缺点

    优点

    一些对数据定时性操作不再依赖外部程序,而直接使用数据库本身提供的功能。可以实现每秒钟执行一个任务,这在一些对实时性要求较高的环境下就非常实用了。

    缺点

    定时触发,不可以调用。

     

    3 创建事件

    一条create event语句创建一个事件。每个事件由两个主要部分组成,第一部分是事件调度(event schedule),表示事件何时启动以及按什么频率启动,第二部分是事件动作(event action ),这是事件启动时执行的代码,事件的动作包含一条SQL语句,它可能是一个简单地insert或者update语句,也可以使一个存储过程或者benin...end语句块,这两种情况允许我们执行多条SQL。不支持DDL语句

    一个事件可以是活动(打开)的或停止(关闭)的,活动意味着事件调度器检查事件动作是否必须调用,停止意味着事件的声明存储在目录中,但调度器不会检查它是否应该调用。在一个事件创建之后,它立即变为活动的,一个活动的事件可以执行一次或者多次。

     

    当一个使用 ON COMPLETION NOT PRESERVE 属性定义的事件最后一次执行后,事件直接就不存在了,不能修改。

     

    .查看:show variables like ’event_scheduler’;

    .开启:set global event_scheduler=1;

    CREATE EVENT EVENT_NAME ON SCHEDULE schedule
     DO
    event_body;
     其中schedule的语法格式为
      AT timestamp [+INTERVAL interval]…|every interval -- 指定事件执行的时间,可以为某时刻点即timestamp,或某时刻点开始的interval时间后,或者为每隔interval时间执行一次
    [starts timestamp [+INTERVAL interval]] -- 设置事件开始执行的时间
    [ends timestamp [+INTERVAL interval]] -- 设置事件终止执行的时间
     
    -- 建立一个事件,用于每分钟向elog表中插入一条数据“now()、’event’”,该事件从5分钟后开始并于20分钟后结束
    ->delimiter //
    -> CREATE EVENT `NewEvent`
    ON SCHEDULE EVERY 1 MINUTE STARTS CURRENT_TIMESTAMP ENDS CURRENT_TIMESTAMP + INTERVAL 20 MINUTE
    ON COMPLETION NOT PRESERVE
    ENABLE
    DO
    insert into elog values(now(),'event');;
    ->//
    (2)修改事件,用于修改时间的状态:alter event event_name {enable|disable};
    (3)删除事件:drop event event_name;
    (4)查看事件:show events

     

    5分钟后将emp_log 这张表 复制到 emp_log_old 并且将emp_log_old备份到D盘

     

    grant file on *.* to root@localhost;在命令行中进行

    CREATE EVENT `NewEvent`
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 5 MINUTE
    ON COMPLETION PRESERVE
    ENABLE
    DO
    Insert into emp_log_old  SELECT * FROM emp_log;
    select * from emp_log_old into outfile 'd:\2.txt';;

    补充:流程控制语句IF, CASE, LOOP, WHILE, ITERATE, LEAVE

    1. 查询每个学生学号、 学生姓名、 课程名称、 成绩 (成绩大于60时的显示及格,小于60时的显示不及格)

    Select stu.SID, stu.SName, `subject`.SubName,
      select_subject.Grade < 60 AS '不及格',
      select_subject.Grade > 60 AS '及格'
    from stu,select_subject,`subject`
    WHERE stu.SID = select_subject.StuID and  select_subject.SubID= `subject`.SubID;
     
    IF
    Select stu.SID, stu.SName, `subject`.SubName,if( select_subject.Grade < 60,'不及格','及格')
      AS '成绩'
    from stu,select_subject,`subject`
    WHERE stu.SID = select_subject.StuID and  select_subject.SubID= `subject`.SubID;
     
    CASE
    Select stu.SID, stu.SName, `subject`.SubName,
    case select_subject.Grade < 60
    WHEN 1 THEN'不及格'
    WHEN 0 THEN '及格'
    else '成绩为空'END
     AS '成绩'
    from stu,select_subject,`subject`
    WHERE stu.SID = select_subject.StuID and  select_subject.SubID= `subject`.SubID;
     
    ELT
    Select stu.SID, stu.SName, `subject`.SubName,
    ELT((select_subject.Grade < 60)+1,'及格','不及格') '成绩'
    from stu,select_subject,`subject`
    WHERE stu.SID = select_subject.StuID and  select_subject.SubID= `subject`.SubID
     
    LOOP,  ITERATE
    CREATE PROCEDURE doiterate(p1 INT)
    BEGIN
      label1: LOOP
        SET p1 = p1 + 1;
    IF p1 < 10 THEN ITERATE label1;
    ELSE
    END IF;
        LEAVE label1;
      END LOOP label1;
      SET @x = p1;
    END
     
    REPEAT
    mysql> CREATE PROCEDURE dorepeat(p1 INT)
        -> BEGIN
        ->   SET @x = 0;
        ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
        -> END
        -> //
    mysql> CALL dorepeat(1000)//
    mysql> SELECT @x//
     
    WHILE
    CREATE PROCEDURE dowhile()
    BEGIN
      DECLARE v1 INT DEFAULT 5;
      WHILE v1 > 0 DO
        ...
        SET v1 = v1 - 1;
      END WHILE;
    END