一. Rank

给出不同的用户的分数,然后根据分数计算排名

(gcdb@localhost) 09:34:47 [mytest]> create table t_rank(id int,score int);
Query OK, 0 rows affected (0.02 sec) (gcdb@localhost) 10:13:03 [mytest]> insert into t_rank values(1, 10), (2, 20), (3, 30), (4, 30), (5, 40), (6, 40);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0 (gcdb@localhost) 10:13:13 [mytest]> select * from t_rank;
+------+-------+
| id | score |
+------+-------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 30 |
| 5 | 40 |
| 6 | 40 |
+------+-------+
6 rows in set (0.00 sec) (gcdb@localhost) 10:13:24 [mytest]> (gcdb@localhost) 10:21:54 [mytest]> SET @prev_value := NUll;
Query OK, 0 rows affected (0.00 sec)
-- 假设比较到第N行,设置一个变量prev_value用于存放第N-1行score的分数
-- 用于比较第N行的score和第N-1行的score
-- prev_value可以理解为 是临时保存第N-1行的score的变量 (gcdb@localhost) 10:25:38 [mytest]> set @rank_count := 0; -- 用于存放当前的排名
Query OK, 0 rows affected (0.00 sec) (gcdb@localhost) 10:25:38 [mytest]> select id, score,
-> case
-> when @prev_value = score then @rank_count
-- 相等则prev_value不变, 并返回rank_count(第一次为NULL,不会相等,所以跳转到下一个when语句)
-> when @prev_value := score then @rank_count := @rank_count + 1
-- 不等,则第N行的score赋值(:=)给prev_value。且rank_count增加1
-> end as rank_column -- case 开始的,end结尾
-> from t_rank
-> order by score desc;
+------+-------+-------------+
| id | score | rank_column |
+------+-------+-------------+
| 5 | 40 | 1 |
| 6 | 40 | 1 |
| 3 | 30 | 2 |
| 4 | 30 | 2 |
| 2 | 20 | 3 |
| 1 | 10 | 4 |
+------+-------+-------------+
6 rows in set (0.00 sec) -- case
-- when [condition_1] then [do_something_1]
-- when [condition_2] then [do_something_2]
-- end
-- 语法: 如果 condition_1条件满足,则执行 do_something_1 然后就跳出,不会执行condition_2;
-- 如果 condition_1条件不满足,则继续执行到 condition_2。以此类推。

-上面语句一句编写

"select  id, score,
case
when @prev_value = score then @rank_count
when @prev_value := score then @rank_count := @rank_count + 1
end as rank_column
from t_rank t,
(SELECT @prev_value := NUll,@rank_count:= 0 ) a
order by score desc;" (gcdb@localhost) 10:26:57 [mytest]> select id, score,
-> case
-> when @prev_value = score then @rank_count
-> when @prev_value := score then @rank_count := @rank_count + 1
-> end as rank_column
-> from t_rank t,
-> (SELECT @prev_value := NUll,@rank_count:= 0 ) a --把@prev_value和@rank_count放到子查询里面
-> order by score desc;
+------+-------+-------------+
| id | score | rank_column |
+------+-------+-------------+
| 5 | 40 | 1 |
| 6 | 40 | 1 |
| 3 | 30 | 2 |
| 4 | 30 | 2 |
| 2 | 20 | 3 |
| 1 | 10 | 4 |
+------+-------+-------------+
6 rows in set (0.00 sec) (gcdb@localhost) 11:06:00 [mytest]>

rank参考资料


二. 视图

官方view文档

2.1、创建视图

--
-- 创建视图,视图名v_rank
--
(gcdb@localhost) 11:34:40 [mytest]> create view v_rank as select * from t_rank; --对select结果增加条件进行过滤后,再创建视图
Query OK, 0 rows affected (0.04 sec) (gcdb@localhost) 11:35:08 [mytest]> show create table v_rank \G; --查看视图表结构
*************************** 1. row ***************************
View: v_rank
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`gcdb`@`%` SQL SECURITY DEFINER VIEW `v_rank` AS select `t_rank`.`id` AS `id`,`t_rank`.`score` AS `score` from `t_rank`
character_set_client: utf8
collation_connection: utf8_general_ci --显示的是视图的定义
1 row in set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 11:35:48 [mytest]> show create table t_rank \G; --查看原表结构
*************************** 1. row ***************************
Table: t_rank
Create Table: CREATE TABLE `t_rank` (
`id` int(11) DEFAULT NULL,
`score` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 11:35:59 [mytest]> select * from v_rank; -- 可以直接查询该视图得结果
+------+-------+
| id | score |
+------+-------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 30 |
| 5 | 40 |
| 6 | 40 |
+------+-------+
6 rows in set (0.00 sec) -- 视图的作用是,可以对开发人员是透明的,屏蔽部分敏感的列
-- 视图在mysql是虚拟表。根据视图的定义,还是取执行定义中的select语句。 -- 只开放部分列
(gcdb@localhost) 11:40:35 [mytest]> create view v_rank_01 as select id from t_rank; -- 只开放id列
Query OK, 0 rows affected (0.00 sec) (gcdb@localhost) 11:42:50 [mytest]> select * from v_rank_01; -- 即使 select * ,也只能看到id列,具有隐藏原来表中部分列的功能
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
+------+
6 rows in set (0.00 sec) -- 不要取用select * from 去创建视图,因为mysql会把*逐个解析成列。
-- 当原来的表结构发生变化时,视图的表结构是不会发生变化的,视图在创建的瞬间,便确定了结构。
-- 比如,当你alter原来的表 增加列(add columns)时,再去查询该视图,新增加的列是不存在的。 (gcdb@localhost) 11:43:20 [mytest]> alter table t_rank add column c int default 0; -- 增加一列名字为c,默认值为0
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0 (gcdb@localhost) 11:44:59 [mytest]> select * from t_rank; -- 查询原表
+------+-------+------+
| id | score | c |
+------+-------+------+
| 1 | 10 | 0 |
| 2 | 20 | 0 |
| 3 | 30 | 0 |
| 4 | 30 | 0 |
| 5 | 40 | 0 |
| 6 | 40 | 0 |
+------+-------+------+
6 rows in set (0.00 sec) (gcdb@localhost) 11:45:08 [mytest]> select * from v_rank; -- 尽管view_rank用select * 创建,但当时没有列c,所以无法得到c列的值
+------+-------+
| id | score |
+------+-------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 30 |
| 5 | 40 |
| 6 | 40 |
+------+-------+
6 rows in set (0.00 sec) (gcdb@localhost) 11:49:35 [mytest]> drop view v_rank_01; --删除视图
Query OK, 0 rows affected (0.01 sec) -- 注意:mysql中的视图都是虚拟表。不像Oracle可以物化成真实存在的表。
-- 每次查询视图,实际上还是去查询的原来的表,只是查询的规则是在视图创建时经过定义的。

2.2、视图的算法

  • 视图的算法(ALGORITHM)有三种方式:

    • UNDEFINED : 默认方式,由MySQL来判断使用下面的哪种算法
    • MERGE每次通过物理表查询得到结果,把结果merge(合并)起来返回
    • TEMPTABLE : 产生一张临时表,把数据放入临时表后,客户端再去临时表取数据(不会缓存

TEMPTABLE 特点 :即使访问条件一样,第二次查询还是会去读取物理表中的内容,并重新生成一张临时表,并不会取缓存之前的表。(临时表是Memory存储引擎,默认放内存,超过配置大小放磁盘)
当查询有一个较大的结果集时,使用TEMPTABLE可以快速的结束对该物理表的访问,从而可以快速释放这张物理表上占用的资源。然后客户端可以对临时表上的数据做一些耗时的操作,而不影响原来的物理表。所以一般我们使用默认的UNDEFINED,由MySQL自己去判断


三. 触发器

官方trigger文档

3.1、触发器介绍

  • 触发器定义

    • 触发器的对象是,当表上出现特定的事件触发该程序的执行
  • 触发器的类型

    • UPDATE

      • update 操作
    • DELETE

      • delete 操作
      • replace 操作
        • 注意:drop,truncate等DDL操作不会触发DELETE
    • INSERT

      • insert 操作
      • load data 操作
      • replace 操作

注意:replace操作会触发两次,一次是UPDATE类型的触发器,一次是INSERT类型的触发器

MySQL 5.6版本同一个类型的触发器只能有一个(单个表)

MySQL 5.7允许多个同一类型的触发器

触发器只触发DML(Data Manipulation Language)操作,不会触发DDL(Data Definition Language)操作 (create,drop等操作)

3.2、触发器语法

  • 创建触发器
CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name -- 触发器名字
trigger_time trigger_event -- 触发时间和事件
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body trigger_time: { BEFORE | AFTER } -- 事件之前还是之后触发
trigger_event: { INSERT | UPDATE | DELETE } -- 三个类型
trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
  • trigger_name:标识触发器名称,用户自行指定;
  • trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
  • trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
  • tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
  • trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。
  • trigger_order:值为FOLLOWS 或者 PRECEDES 后面跟上现有的触发器的名字(注意:这两个触发器的触发条件和触发时间必须一样)。如果为FOLLOWS,这个新的触发器就会在现有的触发器之后被触发。如果为PRECEDES,就会在现有的触发器之前执行。
  • trigger_body:触发器的程序体

由此可见,可以建立6种触发器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、AFTER UPDATE、AFTER DELETE

另外有一个限制是5.7.2之前不能同时在一个表上建立2个相同类型的触发器。

3.3、UPDATE 类型触发器

(gcdb@localhost) 11:49:38 [mytest]> create table t_trigger(name varchar(32),score int(10),primary key(name));
Query OK, 0 rows affected (0.01 sec) (gcdb@localhost) 12:10:21 [mytest]> insert into t_trigger values('fanghao',88),('caowei',59),('xuliuyann',93);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0 (gcdb@localhost) 13:46:20 [mytest]> select * from t_trigger;
+----------+-------+
| name | score |
+----------+-------+
| caowei | 59 |
| fanghao | 88 |
| xuliuyan | 93 |
+----------+-------+
3 rows in set (0.00 sec)
(gcdb@localhost) 14:00:10 [mytest]> delimiter // -- 将语句分隔符定义设置为 // (原来是';') (gcdb@localhost) 14:00:44 [mytest]> create trigger trg_update_score -- 定义触发器名字
-> before update on t_trigger -- 作用在test_trigger_1 更新(update)之前(before)
-> for each row -- 每行
-> begin -- 开始定义
-> if new.score < 60 then set new.score=60; -- 如果新值小于60,则设置为60
-> elseif new.score > 100 then set new.score=100; -- 如果新值大于100,则设置为100
-> end if; -- if 对应结束
-> end; -- begin 对应结束
-> //
Query OK, 0 rows affected (0.01 sec)
(gcdb@localhost) 14:11:52 [mytest]> delimiter ; -- 将语句分隔符定义设置为 ';' 结束符 (gcdb@localhost) 14:02:21 [mytest]> show triggers from mytest \G;
*************************** 1. row ***************************
Trigger: trg_update_score
Event: UPDATE --定义为update类型
Table: t_trigger
Statement: if new.score < 60 then set new.score=60;
elseif new.score > 100 then set new.score=100;
end if
Timing: BEFORE
Created: 2017-12-09 14:00:45.45
sql_mode:
Definer: gcdb@%
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec) ERROR:
No query specified
(gcdb@localhost) 14:21:41 [mytest]> insert into t_trigger values('tom',55); -- 插入tom,分数55
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 14:21:55 [mytest]> select * from t_trigger;
+------+-------+
| name | score |
+------+-------+
| tom | 55 |
+------+-------+
1 row in set (0.00 sec) (gcdb@localhost) 14:21:58 [mytest]> update t_trigger set score=58 where name = 'tom'; --更新tom分数为58
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 (gcdb@localhost) 14:22:09 [mytest]> select * from t_trigger;
+------+-------+
| name | score |
+------+-------+
| tom | 60 | --因为update类型,触发了触发器,score值小60设置为60
+------+-------+
1 row in set (0.00 sec) (gcdb@localhost) 14:22:11 [mytest]> insert into t_trigger values('sim',111); -- 插入sim,分数111
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 14:22:26 [mytest]> update t_trigger set score=2222 where name = 'sim'; -- 插入sim,分数2222,触发了触发器,score值大于100设置为100
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 (gcdb@localhost) 14:22:39 [mytest]> select * from t_trigger;
+------+-------+
| name | score |
+------+-------+
| sim | 100 |
| tom | 60 |
+------+-------+
2 rows in set (0.00 sec) (gcdb@localhost) 14:22:42 [mytest]> update t_trigger set score=99 where name = 'sim'; --更新sim分数为99,触发了触发器但是,分数在60< score <100 之间,不符合更改条件,未设置,还是99
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 (gcdb@localhost) 14:22:49 [mytest]> select * from t_trigger;
+------+-------+
| name | score |
+------+-------+
| sim | 99 |
+------+-------+
2 rows in set (0.00 sec) (gcdb@localhost) 14:22:50 [mytest]>

3.4、INSERT 类型触发器

*创建两张测试表

(gcdb@localhost) 14:44:36 [mytest]> create table t_teachar(tid varchar(30) primary key,tpasswd varchar(32) not null);
Query OK, 0 rows affected (0.01 sec) (gcdb@localhost) 14:46:57 [mytest]> create table t_user(uid varchar(30) primary key,upasswd varchar(32) not null);
Query OK, 0 rows affected (0.01 sec) (gcdb@localhost) 14:56:56 [mytest]> show create table t_user \G;
*************************** 1. row ***************************
Table: t_user
Create Table: CREATE TABLE `t_user` (
`uid` varchar(30) NOT NULL,
`upasswd` varchar(32) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 14:57:09 [mytest]> show create table t_terchar \G;
*************************** 1. row ***************************
Table: t_terchar
Create Table: CREATE TABLE `t_terchar` (
`tid` varchar(30) NOT NULL,
`tpasswd` varchar(32) NOT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 15:13:40 [mytest]> DELIMITER //
(gcdb@localhost) 15:14:02 [mytest]> CREATE TRIGGER trg_insert_after_teachar
-> AFTER INSERT ON t_teachar
-> FOR EACH ROW
-> BEGIN
-> INSERT t_user(uid, upasswd) VALUES(NEW.tid, NEW.tpasswd); --在t_teachar表插入语句之后也在t_user表插入语句
-> END
-> //
Query OK, 0 rows affected (0.01 sec)
(gcdb@localhost) 15:14:02 [mytest]> DELIMITER ; (gcdb@localhost) 15:14:09 [mytest]> show triggers \G;
*************************** 1. row ***************************
Trigger: trg_insert_after_teachar
Event: INSERT
Table: t_teachar
Statement: BEGIN
INSERT t_user(uid, upasswd) VALUES(NEW.tid, NEW.tpasswd);
END
Timing: AFTER
Created: 2017-12-09 15:14:02.07
sql_mode:
Definer: gcdb@%
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci (gcdb@localhost) 15:14:19 [mytest]> insert into t_teachar values('1','aaaa'); --在t_teachar表里插入语句
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 15:14:44 [mytest]> select * from t_user; --在t_user表里面可以看
+-----+---------+
| uid | upasswd |
+-----+---------+
| 1 | aaaa |
+-----+---------+
1 row in set (0.00 sec) (gcdb@localhost) 15:14:56 [mytest]>

3.5、Delete 类型触发器

(gcdb@localhost) 16:01:00 [mytest]> drop table t_user;
Query OK, 0 rows affected (0.01 sec) (gcdb@localhost) 16:04:02 [mytest]> create table t_user(uid varchar(30) primary key,upasswd varchar(32) not null,score int,time timestamp(6) not null default current_timestamp(6) on updatecurrent_timestamp(6));
Query OK, 0 rows affected (0.01 sec) (gcdb@localhost) 16:04:20 [mytest]> drop table t_teachar;
Query OK, 0 rows affected (0.03 sec) (gcdb@localhost) 16:04:40 [mytest]> create table t_teachar(tid varchar(30) primary key,tpasswd varchar(32) not null,score int,time timestamp(6) not null default current_timestamp(6) on update current_timestamp(6));
Query OK, 0 rows affected (0.24 sec) (gcdb@localhost) 16:28:37 [mytest]> insert into t_teachar values('1','aaaa',77,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:30:29 [mytest]> insert into t_teachar values('2','bbbb',88,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:30:29 [mytest]> insert into t_teachar values('3','cccc',99,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:30:46 [mytest]> insert into t_user values('1','aaaa',77,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:31:36 [mytest]> insert into t_user values('2','bbbb',88,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:31:36 [mytest]> insert into t_user values('3','cccc',99,null);
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:34:35 [mytest]> DELIMITER //
(gcdb@localhost) 16:35:23 [mytest]> CREATE TRIGGER trg_delete_teachar
-> AFTER DELETE ON t_teachar
-> FOR EACH ROW
-> BEGIN
-> DELETE FROM t_user WHERE uid = OLD.Tid;
-> END
-> //
Query OK, 0 rows affected (0.00 sec) (gcdb@localhost) 16:35:23 [mytest]> DELIMITER ;
(gcdb@localhost) 16:35:24 [mytest]> select * from t_teachar;
+-----+---------+-------+----------------------------+
| tid | tpasswd | score | time |
+-----+---------+-------+----------------------------+
| 1 | aaaa | 77 | 2017-12-09 16:30:29.668864 |
| 2 | bbbb | 88 | 2017-12-09 16:30:29.669887 |
| 3 | cccc | 99 | 2017-12-09 16:30:30.885201 |
+-----+---------+-------+----------------------------+
3 rows in set (0.00 sec) (gcdb@localhost) 16:35:35 [mytest]> select * from t_user;
+-----+---------+-------+----------------------------+
| uid | upasswd | score | time |
+-----+---------+-------+----------------------------+
| 1 | aaaa | 77 | 2017-12-09 16:31:36.076287 |
| 2 | bbbb | 88 | 2017-12-09 16:31:36.076968 |
| 3 | cccc | 99 | 2017-12-09 16:31:37.350546 |
+-----+---------+-------+----------------------------+
3 rows in set (0.00 sec) (gcdb@localhost) 16:35:40 [mytest]> delete from t_teachar where tid=1;
Query OK, 1 row affected (0.00 sec) (gcdb@localhost) 16:35:49 [mytest]> select * from t_user;
+-----+---------+-------+----------------------------+
| uid | upasswd | score | time |
+-----+---------+-------+----------------------------+
| 2 | bbbb | 88 | 2017-12-09 16:31:36.076968 |
| 3 | cccc | 99 | 2017-12-09 16:31:37.350546 |
+-----+---------+-------+----------------------------+
2 rows in set (0.00 sec) (gcdb@localhost) 16:35:51 [mytest]> select * from t_teachar;
+-----+---------+-------+----------------------------+
| tid | tpasswd | score | time |
+-----+---------+-------+----------------------------+
| 2 | bbbb | 88 | 2017-12-09 16:30:29.669887 |
| 3 | cccc | 99 | 2017-12-09 16:30:30.885201 |
+-----+---------+-------+----------------------------+
2 rows in set (0.00 sec) (gcdb@localhost) 16:36:05 [mytest]>

3.6、显示和删除触发器

(gcdb@localhost) 16:47:15 [mytest]> show triggers \G;
*************************** 1. row ***************************
Trigger: trg_delete_teachar
Event: DELETE
Table: t_teachar
Statement: BEGIN
DELETE FROM t_user WHERE uid = OLD.Tid;
END
Timing: AFTER
Created: 2017-12-09 16:35:23.60
sql_mode:
Definer: gcdb@%
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 16:47:46 [mytest]> drop trigger trg_delete_teachar;
Query OK, 0 rows affected (0.00 sec) (gcdb@localhost) 16:48:24 [mytest]> show triggers \G;
Empty set (0.00 sec) ERROR:
No query specified (gcdb@localhost) 16:48:28 [mytest]>

3.7、触发器总结

  • 触发器对性能有损耗,应当非常慎重使用;

  • 对于事物表,触发器执行失败则整个语句回滚

  • Row格式主从复制,触发器不会在从库上执行

    • 因为从库复制的肯定是主库已经提交的数据,既然已经提交了说明触发器已经被触发过了,所以从库不会执行。
  • 使用触发器时应防止递归执行;

    delimiter //
    create trigger trg_test
    before update on 'test_trigger'
    for each row
    begin
    update test_trigger set score=20 where name = old.name; -- 又触发了update操作,循环触发了
    end;//

3.8、触发器模拟物化视图

  • 物化视图的概念

    • 不是基于基表的虚表
    • 根据基表实际存在的实表
    • 预先计算并保存耗时较多的SQL操作结果(如多表链接(join)或者group by等)
  • 模拟物化视图

(root@localhost) 17:21:28 [mytest]> create table Orders
-> (order_id int unsigned not null auto_increment,
-> product_name varchar(30) not null,
-> price decimal(8,2) not null,
-> amount smallint not null,
-> primary key(order_id));
Query OK, 0 rows affected (0.13 sec) -- 创建Orders表 (root@localhost) 17:26:40 [mytest]> insert into Orders values
-> (null, 'cpu', 135.5 ,1),
-> (null, 'memory', 48.2, 3),
-> (null, 'cpu', 125.6, 3),
-> (null, 'cpu', 105.3, 4);
Query OK, 4 rows affected (0.06 sec) -- 插入测试数据
Records: 4 Duplicates: 0 Warnings: 0 (root@localhost) 17:26:42 [mytest]> select * from Orders;
+----------+--------------+--------+--------+
| order_id | product_name | price | amount |
+----------+--------------+--------+--------+
| 1 | cpu | 135.50 | 1 |
| 2 | memory | 48.20 | 3 |
| 3 | cpu | 125.60 | 3 |
| 4 | cpu | 105.30 | 4 |
+----------+--------------+--------+--------+
4 rows in set (0.00 sec) -- 建立一个模拟物化视图的表(即用这张表来模拟物化视图)
(root@localhost) 17:28:36 [mytest]> CREATE TABLE Orders_MV(
-> product_name VARCHAR(30) NOT NULL
-> , price_sum DECIMAL(8,2) NOT NULL
-> , amount_sum INT NOT NULL
-> , price_avg FLOAT NOT NULL
-> , orders_cnt INT NOT NULL
-> , UNIQUE INDEX (product_name)
-> );
Query OK, 0 rows affected (0.00 sec)
--创建一个普通视图
(root@localhost) 17:28:36 [mytest]> CREATE VIEW v_orders AS SELECT
-> product_name,sum(price),sum(amount),avg(price),count(1)
-> FROM Orders
-> GROUP BY product_name;
Query OK, 0 rows affected (0.04 sec) -- 通过Orders表的数据,将测试数据初始化到Orders_MV表中
(root@localhost) 17:31:22 [mytest]> insert into Orders_MV
-> select product_name, sum(price),sum(amount), avg(price), count(*)
-> from Orders
-> group by product_name;
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0 (root@localhost) 17:32:37 [mytest]> select * from Orders_MV;
+--------------+-----------+------------+-----------+------------+
| product_name | price_sum | amount_sum | price_avg | orders_cnt |
+--------------+-----------+------------+-----------+------------+
| cpu | 366.40 | 8 | 122.133 | 3 |
| memory | 48.20 | 3 | 48.2 | 1 |
+--------------+-----------+------------+-----------+------------+
2 rows in set (0.00 sec) -- 在MySQL workbench中输入,比较方便
delimiter // CREATE TRIGGER tgr_Orders_insert -- 创建触发器为tgr_Orders_insert
AFTER INSERT ON Orders -- 触发器是INSERT类型的,且作用于Orders表
FOR EACH ROW
BEGIN
SET @old_price_sum := 0; -- 设置临时存放Orders_MV表(模拟物化视图)的字段的变量
SET @old_amount_sum := 0;
SET @old_price_avg := 0;
SET @old_orders_cnt := 0;
SELECT -- select ... into ... 在更新Orders_MV之前,将Orders_MV中对应某个产品的信息写入临时变量
IFNULL(price_sum, 0),
IFNULL(amount_sum, 0),
IFNULL(price_avg, 0),
IFNULL(orders_cnt, 0)
FROM
Orders_MV
WHERE
product_name = NEW.product_name INTO @old_price_sum , @old_amount_sum , @old_price_avg , @old_orders_cnt; SET @new_price_sum = @old_price_sum + NEW.price; -- 累加新的值
SET @new_amount_sum = @old_amount_sum + NEW.amount;
SET @new_orders_cnt = @old_orders_cnt + 1;
SET @new_price_avg = @new_price_sum / @new_orders_cnt ; REPLACE INTO Orders_MV
VALUES(NEW.product_name, @new_price_sum,
@new_amount_sum, @new_price_avg, @new_orders_cnt );
-- REPLACE 将对应的物品(唯一索引)的字段值替换new_xxx的值
END;// delimiter ; (root@localhost) 17:37:35 [mytest]> insert into Orders values (null, 'ssd', 299, 3);
Query OK, 1 row affected (0.01 sec) (root@localhost) 17:37:44 [mytest]> insert into Orders values (null, 'memory', 47.9, 5);
Query OK, 1 row affected (0.00 sec) (root@localhost) 17:38:07 [mytest]> select * from Orders_MV;
+--------------+-----------+------------+-----------+------------+
| product_name | price_sum | amount_sum | price_avg | orders_cnt |
+--------------+-----------+------------+-----------+------------+
| cpu | 366.40 | 8 | 122.133 | 3 |
| memory | 96.10 | 8 | 48.05 | 2 | -- 数量自动增加了1,价格也发生了变化
| ssd | 299.00 | 3 | 299 | 1 | -- 新增加的ssd产品
+--------------+-----------+------------+-----------+------------+
3 rows in set (0.00 sec) (root@localhost) 17:38:09 [mytest]> select * from v_orders;
+--------------+------------+-------------+------------+----------+
| product_name | sum(price) | sum(amount) | avg(price) | count(1) |
+--------------+------------+-------------+------------+----------+
| cpu | 366.40 | 8 | 122.133333 | 3 |
| memory | 96.10 | 8 | 48.050000 | 2 |
| ssd | 299.00 | 3 | 299.000000 | 1 |
+--------------+------------+-------------+------------+----------+
3 rows in set (0.00 sec) --
-- IFNULL MySQL内建函数的演示
--
(root@localhost) 08:47:45 [mytest]> select @test;
+-------+
| @test |
+-------+
| NULL | -- 当前会话中没有test变量
+-------+
1 row in set (0.00 sec) (root@localhost) 08:47:46 [mytest]> select ifnull(@test, 100); -- 如果test为NULL,则ifnull返回100
+--------------------+
| ifnull(@test, 100) |
+--------------------+
| 100 | -- ifnull函数return的值是100
+--------------------+
1 row in set (0.00 sec) (root@localhost) 08:48:30 [mytest]> select @test;
+-------+
| @test |
+-------+
| NULL | -- 但是test还是NULL
+-------+
1 row in set (0.00 sec) (root@localhost) 08:48:40 [mytest]> set @test:=200; -- 给test变量赋值为200
Query OK, 0 rows affected (0.00 sec) (root@localhost) 08:48:49 [mytest]> select ifnull(@test, 100); -- 再次ifnull判断,此时test不为null,则返回test变量的值
+--------------------+
| ifnull(@test, 100) |
+--------------------+
| 200 | -- test不为null。返回test的值200
+--------------------+
1 row in set (0.00 sec) --
-- select into 用法
--
(root@localhost) 08:51:19 [mytest]> select @id_1;
+-------+
| @id_1 |
+-------+
| NULL | -- 当前变量id_01为null
+-------+
1 row in set (0.00 sec) (root@localhost) 08:52:10 [mytest]> select @score_1;
+----------+
| @score_1 |
+----------+
| NULL | -- 当前变量score_01为null
+----------+
1 row in set (0.00 sec) (root@localhost) 08:53:56 [mytest]> select * from t_rank;
+------+-------+------+
| id | score | c |
+------+-------+------+
| 1 | 10 | 0 |
| 2 | 20 | 0 |
| 3 | 30 | 0 |
| 4 | 30 | 0 |
| 5 | 40 | 0 |
| 6 | 40 | 0 |
+------+-------+------+
6 rows in set (0.00 sec) (root@localhost) 08:55:04 [mytest]> select id,score from t_rank where id =1 into @id_01,@score_01;-- 选择id=1的记录,将对应的id和score赋值给变量 id_01 和 score_01
Query OK, 1 row affected (0.00 sec) (root@localhost) 08:55:27 [mytest]> select @id_01;
+-------+
| @id_1 |
+-------+
| 1 |
+-------+
1 row in set (0.00 sec) (root@localhost) 08:55:41 [mytest]> select @score_01;
+-----------+
| @score_01 |
+-----------+
| 10 |
+-----------+
1 row in set (0.00 sec) -- 触发器对性能会有影响,相当于在一个事物中插入了其他的事物

013:Rank、视图、触发器、MySQL内建函数的更多相关文章

  1. Mysql 视图,触发器,存储过程,函数,事务

    视图 视图虚拟表,是一个我们真实查询结果表,我们希望将某次查询出来的结果作为单独的一个表,就叫视图,无法对图字段内容进行增删改. --格式: CREATE VIEW 视图名字 AS 操作; --比如: ...

  2. mysql 视图 触发器 事物 存储过程 函数 流程控制

    1.视图 *** 视图是有一条sql语句的查询结果构成的虚拟表 其不是物理存在的 使用方式与普通表相同 视图的作用1.简化sql语句的编写 2.限制可以查看的数据 可以使用权限来完成 权限某一个库 的 ...

  3. MySQL 视图触发器事务存储过程函数

    事务  致命三问 什么是事务:开启了一个包含多条SQL语句的事务,这些SQL语句要么都执行成功,要么有别想成功:例如A向B转账,二人账户并不属于一家银行,在转账过程中由于网络问题,导致A显示转账 成功 ...

  4. MySQL拓展 视图,触发器,事务,存储过程,内置函数,流程控制,索引,慢查询优化,数据库三大设计范式

    视图: 1.什么是视图 视图就是通过查询得到一张虚拟表,然后保存下来,下次直接使用即可 2.为什么要用视图 如果要频繁使用一张虚拟表,可以不用重复查询 3.如何使用视图 create view tea ...

  5. MySQL 视图 触发器 事务 存储过程 函数 流程控制 索引与慢查询优化

    视图 1.什么是视图? 视图就是通过查询得到的一张虚拟表,然后保存下来,下次可直接使用 2.为什么要使用视图? 如果要频繁使用一张虚拟表,可以不用重复查询 3.如何使用视图? create view ...

  6. mysql 视图 触发器 存储过程 函数事务 索引

    mysql 视图 触发器 存储过程 函数事务 索引 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当 ...

  7. MySQL 查询 存储过程 视图 触发器 函数 索引 建表语句 数据库版本 当前登录用户 当前数据库名称

    MySQL 查询 存储过程 视图 触发器 函数 索引 建表语句 数据库版本 当前登录用户 当前数据库名称   INFORMATION_SCHEMA.TABLES INFORMATION_SCHEMA. ...

  8. day40 mycql 视图,触发器,存储过程,函数

    视图,触发器,存储过程,自定义函数 -- 回顾 1.mysql 约束 1.非空 not null 2. 主键约束 primary key 3. 唯一约束 unique 4. 外键约束 foreign ...

  9. python 全栈开发,Day64(视图,触发器,函数,存储过程,事务)

    昨日内容回顾 pymysql:属于python的一个模块 pip3 install pymysql conn = pymysql.connect(...,charset = 'uft8') 创建游标 ...

随机推荐

  1. python装饰器中functools.wraps的作用详解

    直接上代码看效果: # 定义一个最简单的装饰器 def user_login_data(f): def wrapper(*args, **kwargs): return f(*args, **kwar ...

  2. Spring报错: org.springframework.beans.factory.support.BeanDefinitionValidationException: Couldn't find an init method named 'init' on bean with name 'car'(待解答)

    在Spring工程里,有一个Car类的bean,Main.java主程序,MyBeanPostProcessor.java是Bean后置处理器. 文件目录结构如下: Car.java package ...

  3. Chrome自定义最小字号

    ============= ============== =======================

  4. win7下pyhton3.6创建django2的pycharm项目

    1.进入python虚拟环境: workon workon oneenv 2. 在虚拟环境中安装django,也可以使用pycharm上的自动安装,但那个比较慢,所有还是在cmd中安装的好 pip i ...

  5. webpack 实现自动刷新,复制文件,实现开发环境和发布环境

    webpack例子:https://github.com/Aquarius1993/webpackDemo 安装: webpack , webpack-dev-server 1.如何在使用webpac ...

  6. UNIX环境高级编程 文件I/O

    大多数文件I/O 只需要用到 5个函数 :    open , read , write , lseek , close 本章描述的都是不带缓冲的I/O(read write 都调用内核中的一个系统调 ...

  7. 【剑指offer】丑数,C++实现

    原创博文,转载请注明出处!本题牛客网地址 博客文章索引地址 博客文章中代码的github地址 1. 题目 2. 思路 空间换时间的方法.由于题目要求按序查找丑数,可以采用辅助容器vector按序存储丑 ...

  8. Python timedelta

    datetime.timedelta对象代表两个时间之间的的时间差,两个date或datetime对象相减时可以返回一个timedelta对象.   构造函数: class datetime.time ...

  9. BZOJ1183 Croatian2008 Umnozak 【数位DP】*

    BZOJ1183 Croatian2008 Umnozak Description 定义一个数的digit-product是它的各个位上的数字的乘积,定义一个数的self-product是它本身乘以它 ...

  10. 《DSP using MATLAB》示例Example 8.14

    %% ------------------------------------------------------------------------ %% Output Info about thi ...