一. 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. tooltip提示框组件

    Tooltip 提示框组件 可独立于其他组件通过$.fn.tooltip.defaults重写默认的defaults.当用户移动鼠标指针在某个元素上时,出现提示信息窗口来显示额外信息.提示内容可以包含 ...

  2. mysql function动态执行不同sql语句

    create procedure cps() begin ) default 'user'; set strSql = concat('select * from ',table_user); pre ...

  3. is null 和=null的区别

    数据库中 null 表示 不可知,不确定 所以 判断都用 字段 is null的方式进行判断 而 = null .<> null 的判断结果,仍然是不可知,不确定,所以 不会返回任何结果. ...

  4. APUE学习笔记——8.11 实际用户ID、有效用户ID、设置用户ID

    用户ID的基本概念 在Unix系统中,很多操作涉及到权限问题,这些权限涉及到用户ID和组ID的概念.     组ID和用户ID的原理和相关内容是类似的.下面介绍用户ID.     我们常见见到三种关于 ...

  5. L164

    “TAKE ONLY memories, leave only footprints” is more than a hiking motto at the Sagarmatha National P ...

  6. IE11降级到IE8

  7. Python IDLE 的使用与调试

    Python IDLE 是Python 安装包自带的集成开发环境.IDLE集成了Python 解释器.编辑器与调试器.适用于初学者了解Python 语法知识.1.使用 Python IDLE 编辑Py ...

  8. Realm的常规使用与线程中的坑

    结识 Realm 的催化剂 在我们公司的项目迭代中,由于在之前的聊天这个模块关于用户信息的传值有问题,而之前因为项目经过很多开发者的手,且不提整体的架构有多混乱,就单说缓存这块,就是乱的不行,有的地方 ...

  9. 网络编程 socket编程 - Asyncsocke

    简单的聊天程序:http://blog.csdn.net/chang6520/article/details/7967662 iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 c ...

  10. tomcat错误:The page you tried to access (/manager/login.do) does not exist

    今天在idea上跑一个项目,所有配置都正常,其他接口测试也正常.唯独“/manage/user”接口在测试的时候后台没反应,也就是程序根本没往下走,postman测试显示如下: 浏览器范围url连接显 ...