013:Rank、视图、触发器、MySQL内建函数
一. 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]>
二. 视图
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自己去判断
三. 触发器
3.1、触发器介绍
触发器定义
- 触发器的对象是
表
,当表上出现特定的事件
时触发
该程序的执行
- 触发器的对象是
触发器的类型
UPDATE
- update 操作
DELETE
- delete 操作
- replace 操作
- 注意:drop,truncate等DDL操作
不会触发
DELETE
- 注意:drop,truncate等DDL操作
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内建函数的更多相关文章
- Mysql 视图,触发器,存储过程,函数,事务
视图 视图虚拟表,是一个我们真实查询结果表,我们希望将某次查询出来的结果作为单独的一个表,就叫视图,无法对图字段内容进行增删改. --格式: CREATE VIEW 视图名字 AS 操作; --比如: ...
- mysql 视图 触发器 事物 存储过程 函数 流程控制
1.视图 *** 视图是有一条sql语句的查询结果构成的虚拟表 其不是物理存在的 使用方式与普通表相同 视图的作用1.简化sql语句的编写 2.限制可以查看的数据 可以使用权限来完成 权限某一个库 的 ...
- MySQL 视图触发器事务存储过程函数
事务 致命三问 什么是事务:开启了一个包含多条SQL语句的事务,这些SQL语句要么都执行成功,要么有别想成功:例如A向B转账,二人账户并不属于一家银行,在转账过程中由于网络问题,导致A显示转账 成功 ...
- MySQL拓展 视图,触发器,事务,存储过程,内置函数,流程控制,索引,慢查询优化,数据库三大设计范式
视图: 1.什么是视图 视图就是通过查询得到一张虚拟表,然后保存下来,下次直接使用即可 2.为什么要用视图 如果要频繁使用一张虚拟表,可以不用重复查询 3.如何使用视图 create view tea ...
- MySQL 视图 触发器 事务 存储过程 函数 流程控制 索引与慢查询优化
视图 1.什么是视图? 视图就是通过查询得到的一张虚拟表,然后保存下来,下次可直接使用 2.为什么要使用视图? 如果要频繁使用一张虚拟表,可以不用重复查询 3.如何使用视图? create view ...
- mysql 视图 触发器 存储过程 函数事务 索引
mysql 视图 触发器 存储过程 函数事务 索引 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当 ...
- MySQL 查询 存储过程 视图 触发器 函数 索引 建表语句 数据库版本 当前登录用户 当前数据库名称
MySQL 查询 存储过程 视图 触发器 函数 索引 建表语句 数据库版本 当前登录用户 当前数据库名称 INFORMATION_SCHEMA.TABLES INFORMATION_SCHEMA. ...
- day40 mycql 视图,触发器,存储过程,函数
视图,触发器,存储过程,自定义函数 -- 回顾 1.mysql 约束 1.非空 not null 2. 主键约束 primary key 3. 唯一约束 unique 4. 外键约束 foreign ...
- python 全栈开发,Day64(视图,触发器,函数,存储过程,事务)
昨日内容回顾 pymysql:属于python的一个模块 pip3 install pymysql conn = pymysql.connect(...,charset = 'uft8') 创建游标 ...
随机推荐
- java中的一些执行顺序,代码块,静态,构造,成员。。。。(转的)
Java初始化顺序(转来的) 1在new B一个实例时首先要进行类的装载.(类只有在使用New调用创建的时候才会被java类装载器装入) 2,在装载类时,先装载父类A,再装载子类B3,装载父类A后,完 ...
- (转载)Android学习笔记⑨——android.content.ActivityNotFoundException异常处理
异常1:Java.lang.ClassNotFoundException 08-13 18:29:22.924: E/AndroidRuntime(1875):Caused by: Java.lang ...
- c# DataTable行转列
/// <summary> /// datatable行转列 /// </summary> /// <param name="dtSrc">来源 ...
- for循环打印等腰三角形、直角三角形、菱形
一.等腰三角形 package s1; import java.util.Scanner; public class C31 { public static void main(String[] ar ...
- asp.net设置gridview页码显示遇到的问题
问题:分页部分显示的页码撑开占满整个表格底部 解决方法: 1.通过浏览器察看源,发现是分页部分的table样式受到整个页面的table设置的样式的影响,分页是一个tr里面的td里面的table 2.设 ...
- Dom4j下载及使用Dom4j读写XML简介(转)
Dom4j下载及使用Dom4j读写XML简介 要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/目前最新dom4j包下载地址:ht ...
- charles抓包--手机端
Fiddler和charles都是抓包工具,可以抓到pc端的请求,手机上设置代理后也可以抓到手机上的请求,也可以修改请求数据和返回的数据. 在接口已经使用的时候,比如说已经用到了app上,app端测试 ...
- python的if判断补充
python的if判断补充 exit_flag = False # 标识符 if exit_flag == False: print('exit_flag == False') exit_flag = ...
- PHP中 public、protected 和 privare的区别
权限:public>protected>private public:谁都可以调用 protected:只有自己和派生类可以调用 privare:只有自己可以调用
- 程序设计入门-C语言基础知识-翁恺-第三周:循环-详细笔记(三)
目录 第三周:循环 3.1 循环 3.2 循环计算 3.3 课后习题 3.4 讨论题(不需要掌握) 第三周:循环 3.1 循环 while循环 语法: while(条件表达式){ //循环体语句 } ...