学习要点

  • MySQL系统函数
  • MySQL视图
  • MySQL存储过程
  • MySQL自定义函数
  • MySQL触发器
  • MySQL事务
  • MySQL事件

MySQL系统函数

数学函数

  • 获取整数的函数:CEIL(x)、CEILING(x)、FLOOR(x)
CEIL(x)、CEILING(x):返回不小于x的BIGINT整数值。

FLOOR(x):向下取整,返回BIGINT。

   

  • 获取随机数函数:RAND()、RAND(X)
返回[0,1]之间的浮点数。X用来产生重复的随机数。

上机练习1:#获得[1-99]之间的随机数

SELECT FLOOR(RAND()*98)+1;

  

  • ROUND(x)、ROUND(x,y)、TRUNCATE(x,y)
ROUND(x)四舍五入。

ROUND(x,y)返回接近x的数,保留小数点y位。y为负数则去除小数点左边y位。

TRUNCATE(x,y)返回舍去小数点后y位的数字。y为负数则去除小数点左边y位。

  

字符串函数

  • 计算字符串字符数的函数:CHAR_LENGTH()
  • 计算字符串长度的函数:LENGTH()
  • 字母大小写转换函数:LOWER()、LCASE()、UPPER()、UCASE()
  • 字符串比较函数:STRCMP(S1,S2)  相等返回0,S1<S2返回-1,否则返回1
  • 字符串截取:SUBSTRING(Str,offset,len)。Offset为负数则从字符串结尾往字符串开始方向计算。
  • 获取当前日期函数:CURDATE()、CURRENT_DATE()
  • 获取当前时间函数:CRUTIME()、CURRENT_TIME()
  • 获得当前时间:now();
  • 数据表中自动插入时间戳:字段类型设置为:timestamp 默认值设置为:default current_timestamp

日期和时间函数

  • 获取当前日期函数:CURDATE()、CURRENT_DATE()
  • 获取当前时间函数:CRUTIME()、CURRENT_TIME()
  • 获得当前时间:now();
  • 数据表中自动插入时间戳:字段类型设置为:timestamp 默认值设置为:default current_timestamp

条件判断函数

  • IF(expr,v1,v2):expr表达式成立,返回V1,否则返回V2。
  • IFNULL(v1,v2):V1不为空,返回V1;否则返回V2。

上机练习2:修改学生信息返回,地址为null返回‘地址为空’

  • CASE函数
CASE 表达式

WHEN V1 THEN …

WHEN V2 THEN …

WHEN V3 THEN …

…

ELSE …

END

  

用法示例:

系统信息函数

  • 获取MySQL版本号:VERSION()
  • 获取当前进程的mysql访问id:CONNECTION_ID()

  • 获取最后一个生成的ID的值的函数:LAST_INSERT_ID();

加密函数

  • PASSWORD(str)加密:系统加密使用,比如数据库管理员用户加密。
  • MD5(str)加密:应用程序使用。
  • ENCODE(被加密字符串,加密密码),DECODE(已加密字符串,解密密码)

其他函数

IP地址与数字相互转换函数:INET_ATION(‘a.b.c.d’)、INET_NTION(num)

转换算法:a*256*256*256+b*256*256+c*256+d*1

MySQL视图

视图的定义

  • 视图是一个虚拟表:表示一张表的部分数据或多张表的综合数据;其结构和数据是建立在对表的查询基础上。
  • 实际上视图就是一条SELECT或者INSERT、UPDATE、DELETE语句。
  • 视图中不存放数据。数据存放在视图所引用的原始表中。
  • 一个原始表,根据不同用户的不同需求,可以创建不同的视图
  • MySQL从5.0版本开始支持视图。

为什么使用视图

  • 不同的人员关注不同的数据
  • 保证信息的安全性

视图的用途

  • 筛选表中的行
  • 防止未经许可的用户访问敏感数据
  • 降低数据库的复杂程度
  • 将多个物理数据库抽象为一个逻辑数据库

如何创建视图

1、方式一:通过视图创建工具可视化创建视图

2、方式二:通过SQL语句创建视图

语法格式:

CREATE  [OR  REPLACE]  VIEW  view_name  AS  SELECT_statement

创建单表视图(支持增删改查操作)

创建多表视图(不推荐进行增删改)

查看视图

使用DESC查看视图结构

使用 [ SHOW TABLE STATUS LIKE ‘视图名’] 查看视图基本信息

使用 [SHOW CREATE VIEW ‘视图名’] 查看视图详细信息

从information_schema.views表中查看数据库所有已定义的视图

修改视图

CREATE  [OR REPLACE]  view_name  AS  SELECT_statement

  

语法同创建视图。

或者:

ALTER view_name  AS  SELECT_statement

  

更新视图

语法格式:

UPDATE 视图名称  SET 字段=value

  

注意:会更新原始表数据

从视图中delete一条记录,也将会删除原始表数据。

以下情况,无法通过视图更新操作:

1、视图中不包含基本表中的非空字段;

2、SELECT子句中使用了数学表达式;

3、SELECT子句中使用了聚合函数;

4、SELECT子句中使用了:DISTINCT,UNION,TOP,GROUP BY或者HAVING子句

删除视图

DROP  VIEW [ IF EXISTIS ] 视图名

上机练习3:创建视图vw_getresult,实现以下功能

MySQL存储过程

存储过程定义

存储过程就是一条或者多条SQL语句的集合,保存在服务器数据库里。

  • 优点:

1、避免在网上从传输大量的SQL语句,提高网络速度;

2、防止SQL语句被截取和盗用,提高信息安全性;

3、存储过程保存在服务器端,已经被编译,执行效率高。

  • 缺点:移植性差。

语法格式

CREATE  PROCEDURE sp_name ( [proc_parameter])

[characteristics … ]  routine_body

  

  • proc_parameter:存储过程参数,有三种类型

    [ IN | OUT | INOUT ] proc_parameter

  • characteristics:存储过程特性。

    包含语言、结果、SQL限制、权限、备注等信息的设置。

  • routine_body:用BEGIN … END 来表示的SQL代码块

创建无参存储过程

  • 在控制台创建:

  DELIMITER:将MySQL的结束符设置为//。因为存储过程中的“;”会被控制台终端当成SQL的结束符号。重新定义结束符号:DELIMITER ; //。

  • 在navicat查询编辑器中创建存储过程

  • 执行存储过程

  • 删除存储过程

  • 查看数据库中已定义的存储过程或者函数

  • 查看存储过程定义

上机练习4:创建存储过程sp_getteaminfo(),实现球队信息的查询。

创建带输入参数的存储过程

  • 创建

  • 调用

创建带输入输出参数的存储过程

  • 创建

  • 调用

方式1:在控制台调用,设定自定义变量@变量名 接收输出参数。

方式2:在navicat存储过程编辑器中输入参数运行,多个参数之间‘,’号隔开,字符串要使用单引号。

上机练习5:创建存储过程sp_getstudentnamebyno(IN inno,OUT name CHAR(20)),实现学生信息查询。

MySQL自定义函数

语法格式

CREATE  FUNCTION func_name ( [func_parameter])

RETURNS type

[characteristics … ]  routine_body

  

  • func_name自定义函数名
  • RETURNS type:函数返回的数据类型
  • func_parameter:自定义函数参数,有三种类型

    [ IN | OUT | INOUT ] func_parameter

  • characteristics:存储过程特性。

    包含语言、结果、SQL限制、权限、备注等信息的设置。

  • routine_body:用BEGIN … END 来表示的SQL代码块。

自定义函数示例

注意:

1、和存储过程不同,函数的参数不需要指定IN、OUT、INOUT。

2、函数内只有一条执行SQL语句,可以不使用BEGIN-END。否则需要BEGIN-END。

3、 函数调用直接使用SELECT调用。

上机练习6:创建函数fn_getstudentnamebyno(inno INT),实现学生信息查询。

MySQL触发器

触发器的定义

触发器与存储过程一样,都是存储在MySQL的一段程序。

存储过程的执行采用CALL调用的方式,而触发器的执行是由事件来触发执行的,这些事件包括:INSERT、UPDATE、DELETE。

语法格式

CREATE  TRIGGER  trigger_name  trigger_time  trigger_event

ON  table_name  FOR  EACH  ROW  trigger_stmt

参数说明:

  • trigger_name:触发器名称
  • trigger_time:触发时机,值为after或者before
  • trigger_event:触发事件——INSERT、UPDATE、DELETE
  • table_name:建立出发器的数据表
  • trigger_stmt:触发器程序体
  • FOR EACH ROW:通知触发器数据表行记录变更的时候触发

创建一条语句的触发器

创建表tgtest和触发器tg_sum_tritest_amount:

#创建ACCOUNT表
DROP TABLE IF EXISTS tgtest;
CREATE TABLE IF NOT EXISTS tgtest(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT'编号',
amount INT UNSIGNED NOT NULL COMMENT'金额'
)ENGINE=INNODB DEFAULT CHARSET=UTF8; #创建触发器:向tritest插入数据前,对amount字段进行求和
CREATE TRIGGER tg_sum_tritest_amount BEFORE INSERT
ON tgtest
FOR EACH ROW SET @sum=@sum+NEW.amount;

  

查看数据库中触发器:

SELECT * FROM information_schema.TRIGGERS;

测试触发器:

#测试触发器
SET @sum=0;
INSERT INTO tgtest VALUES(DEFAULT,3),(DEFAULT,5);
SELECT @sum;

  

测试结果:

删除触发器:

# 删除触发器
DROP TRIGGER tg_sum_tritest_amount;

  

创建多条执行语句的触发器

问题:有两张MyISAM类型的数据表,一张是商品表,一张是订单表,当增删改订单表的时候,如何使用触发器修改商品表的库存?

示例代码:

#创建商品表
DROP TABLE IF EXISTS good;
CREATE TABLE IF NOT EXISTS good(
gid BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '商品编号',
gname char(20) NOT NULL COMMENT '品名',
gcount INT UNSIGNED NOT NULL COMMENT '库存'
)ENGINE=MyISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=100000; #创建订单表
DROP TABLE IF EXISTS saleorder;
CREATE TABLE IF NOT EXISTS saleorder(
oid BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '订单编号',
gid BIGINT UNSIGNED NOT NULL COMMENT '商品id',
ocount INT UNSIGNED NOT NULL COMMENT '订单商品数量'
)ENGINE=MyISAM DEFAULT CHARSET=UTF8 AUTO_INCREMENT=3502002016000; # 商品表插入数据
INSERT INTO good(gname,gcount) VALUES('iphone x',100);
SELECT * FROM good; # 创建订单时候修改商品表的库存
DROP TRIGGER tg_corder_mgood;
CREATE TRIGGER tg_corder_mgood AFTER INSERT ON saleorder
FOR EACH ROW
UPDATE good SET gcount=gcount-NEW.ocount WHERE gid=NEW.gid; # 下单
INSERT INTO saleorder(gid,ocount) VALUES(100000,11); # 查看商品表和订单表的数据
SELECT * FROM good;
SELECT * FROM saleorder; # 修改订单时候修改商品表的库存
DROP TRIGGER tg_morder_mgood;
CREATE TRIGGER tg_morder_mgood AFTER UPDATE ON saleorder
FOR EACH ROW
UPDATE good SET gcount=gcount+OLD.ocount-NEW.ocount WHERE gid=OLD.gid; # 修改订单
UPDATE saleorder SET ocount=ocount-1 WHERE oid=3502002016000; -- 订单商品数量-1
SELECT * FROM good;
SELECT * FROM saleorder; # 删除订单的时候修改商品表的库存
DROP TRIGGER tg_dorder_mgood;
CREATE TRIGGER tg_dorder_mgood AFTER DELETE ON saleorder
FOR EACH ROW
UPDATE good SET gcount=gcount+OLD.ocount WHERE gid=OLD.gid; # 删除订单
DELETE FROM saleorder WHERE oid=3502002016000;
SELECT * FROM good;
SELECT * FROM saleorder;

  

NEW和OLD:使用“NEW.字段名”和“OLD.字段名”的SQL语句变量称为过渡变量。

NEW:只能存在于INSERT语句中。“NEW.字段名”表示获取引起触发器触发的SQL语句中对应字段的值。

OLD:只能存在于DELETE语句中。“OLD.字段名”表示获取引起触发器触发的SQL语句对应数据表中相应记录对应字段的值。

只有在UPDATE语句中可以同时存在NEW和OLD关键字。

上机练习7:创建多条语句触发器,实现订单表的增删改的同时触发修改商品表信息。

MySQL事务

事务的定义

  • 事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列操作
  • 多个操作作为一个整体向系统提交,要么都执行、要么都不执行
  • 事务是一个不可分割的工作逻辑单元

事务的特性

事务必须具备以下四个属性,简称ACID 属性:

  • 原子性(Atomicity):事务是一个完整的操作,事务的各步操作是不可分的(原子的),要么都执行,要么都不执行。
  • 一致性(Consistency):当事务完成时,数据必须处于一致状态。
  • 隔离性(Isolation):并发事务之间彼此隔离、独立,它不应以任何方式依赖于或影响其他事务。
  • 永久性(Durability):事务完成后,它对数据库的修改被永久保持。
  • 注意:InnoDB和BDB引擎表才支持事务。
  • 问题:解决转账问题。

事务综合示例:

USE mybank;

# 模拟银行数据表1
DROP TABLE IF EXISTS bank1;
CREATE TABLE IF NOT EXISTS bank1(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '账号',
username CHAR(20) NOT NULL COMMENT '户名',
amount INT UNSIGNED NOT NULL COMMENT '余额'
)ENGINE=INNODB DEFAULT CHARSET=UTF8 AUTO_INCREMENT=1120553244123; # 模拟银行数据表2
DROP TABLE IF EXISTS bank2;
CREATE TABLE IF NOT EXISTS bank2(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '账号',
username CHAR(20) NOT NULL COMMENT '户名',
amount INT UNSIGNED NOT NULL COMMENT '余额'
)ENGINE=INNODB DEFAULT CHARSET=UTF8 AUTO_INCREMENT=2234753244567; # 两个银行分别初始化两个账户
INSERT INTO bank1(id,username,amount) VALUES(DEFAULT,'张三',800);
INSERT INTO bank2(id,username,amount) VALUES(DEFAULT,'李四',1200); # 查询数据
SELECT * FROM bank1;
SELECT * FROM bank2; #模拟转账
-- 张三转账850元给李四
UPDATE bank2 SET amount=amount+850 WHERE id=2234753244567; -- 李四
UPDATE bank1 SET amount=amount-850 WHERE id=1120553244123; -- 张三 /** 解决方案1 */
#关闭自动事务提交
SET AUTOCOMMIT =0; -- 1表示开启
UPDATE bank2 SET amount=amount+850 WHERE id=2234753244567; -- 李四
UPDATE bank1 SET amount=amount-850 WHERE id=1120553244123; -- 张三
ROLLBACK; -- 异常则回滚
COMMIT; -- 提交事务 /** 解决方案2 */
# 开启事务
SET AUTOCOMMIT =1; -- 自动提交事务打开
START TRANSACTION; -- 开始事务(事务打开的情况下需要调用该语句,否则无法回滚)
UPDATE bank2 SET amount=amount+850;
UPDATE bank1 SET amount=amount-850;
COMMIT; -- 提交事务(关闭事务)
ROLLBACK; -- 放弃事务(关闭事务) # 折返点
SELECT * FROM bank1;
SET AUTOCOMMIT =0;
UPDATE bank1 SET amount=amount+1;
UPDATE bank1 SET amount=amount+1;
UPDATE bank1 SET amount=amount+1;
SAVEPOINT a_ponit;
UPDATE bank1 SET amount=amount+1;
UPDATE bank1 SET amount=amount+1;
UPDATE bank1 SET amount=amount+1;
UPDATE bank1 SET amount=amount+1;
ROLLBACK TO SAVEPOINT a_ponit;
ROLLBACK; -- 全部回滚
COMMIT; -- 提交事务 # 使用存储过程实现转账事务处理
-- 转账存储过程
DROP PROCEDURE IF EXISTS transamount;
CREATE PROCEDURE transamount ()
BEGIN
DECLARE trans_error INT DEFAULT 0; -- 声明变量trans_error保存错误信息
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET trans_error = 1; -- 定义错误处理方式:continue或者exit,这里选择continue
SET AUTOCOMMIT =0; -- 关闭MySQL事务自动提交
START TRANSACTION; -- 开启事务
UPDATE bank1 SET amount=amount-850;
UPDATE bank2 SET amount=amount+850;
IF trans_error = 1 THEN
ROLLBACK; -- 错误则回滚
SELECT '转账失败';
ELSE
COMMIT; -- 转账成功提交事务
SELECT '转账成功';
END IF;
SET AUTOCOMMIT =1; -- 打开MySQL事务自动提交
END; # 测试存储过程转账
SELECT * FROM bank1;
SELECT * FROM bank2;
CALL transamount();

上机练习8:创建存储过程实现转账事务要求。

MySQL事件

在系统管理或者数据库管理中,经常要周期性的执行某一个命令或者SQL语句。Mysql在5.1以后推出了事件调度器(Event Scheduler),和linux的cron功能一样,能方便地实现 mysql数据库的计划任务,而且能精确到秒。使用起来非常简单和方便。

如何开启事件

查看mysql服务器上的事件是否开启

SHOW VARIABLES LIKE 'event_scheduler';
SELECT @@event_scheduler;
SHOW PROCESSLIST; -- 查看mysql服务器在运行线程

  

如果看到event_scheduler为on或者PROCESSLIST中显示有event_scheduler的信息说明就已经开启了事件。如果显示为off或者在PROCESSLIST中查看不到event_scheduler的信息,那么就说明事件没有开启,我们需要开启它。

如何开启事件?

  • 通过动态参数修改
SET GLOBAL event_scheduler = ON;  //重启后失效
  • 更改配置文件然后重启
my.ini文件的[mysqld]部分添加:event_scheduler=ON
  • 通过制定事件参数启动
mysqld ... --event_scheduler=ON

  

Mysql事件的语法

  • 创建事件语法
CREATE
[DEFINER = { user | CURRENT_USER }] EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment']
DO event_body; schedule:
AT timestamp [+ INTERVAL interval] ... | EVERY interval [STARTS timestamp [+ INTERVAL interval] ...] [ENDS timestamp [+ INTERVAL interval] ...] interval:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

  

参数说明:

DEFINER: 定义事件执行的时候检查权限的用户。

ON SCHEDULE schedule: 定义执行的时间和时间间隔。

ON COMPLETION [NOT] PRESERVE: 定义事件是一次执行还是永久执行,默认为一次执行,即NOT PRESERVE。

ENABLE | DISABLE | DISABLE ON SLAVE: 定义事件创建以后是开启还是关闭,以及在从上关闭。如果是从服务器自动同步主上的创建事件的语句的话,会自动加上DISABLE ON SLAVE。

COMMENT 'comment': 定义事件的注释。

  • 修改事件语法
ALTER
[DEFINER = { user | CURRENT_USER }] EVENT event_name [ON SCHEDULE schedule] [ON COMPLETION [NOT] PRESERVE]
[RENAME TO new_event_name] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] [DO event_body]

  

  • 删除事件语法
DROP EVENT [IF EXISTS] event_name

  

Mysql事件应用举例

  • 简单应用
# 开启事件(MySQL服务重启失效)
SET GLOBAL event_scheduler = ON; # 创建事件测试表
DROP TABLE IF EXISTS etest;
CREATE TABLE IF NOT EXISTS etest (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`data` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1000; # 创建一个每隔10秒往test表中插入一条数据的事件(立刻开始运行)
DROP EVENT IF EXISTS ev_insert_data;
CREATE EVENT IF NOT EXISTS ev_insert_data ON SCHEDULE EVERY 10 SECOND
ON COMPLETION PRESERVE
DO INSERT INTO etest(id,data) VALUES(DEFAULT,NOW()); # 查询数据
SELECT * FROM etest; # 创建一个1分钟后清空test表数据的事件
DROP EVENT IF EXISTS ev_clear_data;
CREATE EVENT IF NOT EXISTS ev_clear_data
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO TRUNCATE TABLE etest; # 某一时刻清除数据
DROP EVENT IF EXISTS ev_clear_data_attime;
CREATE EVENT IF NOT EXISTS ev_clear_data_attime
ON SCHEDULE AT TIMESTAMP '2018-10-10 00:00:00'
DO TRUNCATE TABLE etest; # 某个时间段执行事件
DROP EVENT IF EXISTS ev_do_between_time;
CREATE EVENT IF NOT EXISTS ev_do_between_time
ON SCHEDULE EVERY 3 SECOND
STARTS '2018-08-22 21:49:00'
ENDS '2018-08-22 21:49:00'+ INTERVAL 10 MINUTE
ON COMPLETION PRESERVE
DO INSERT INTO etest(id,data) VALUES(DEFAULT,NOW());

  

  • MySQL事件通常用来调用存储过程
# 调用存储过程(一分钟后转账)
DROP EVENT IF EXISTS ev_call_trans_proc;
CREATE EVENT IF NOT EXISTS ev_call_trans_proc
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO call transamount(); SELECT * FROM bank1;
SELECT * FROM bank2;

  

  

最新文章

  1. 我的LESS编译方案
  2. GJM : 用Unity模仿CSGO里的火焰效果 [转载]
  3. Ztree 随笔记
  4. struts框架学习过程中的问题
  5. ELK-Python(一)
  6. ELF--动态链接
  7. 处理get中的中文乱码情况
  8. 谈谈我对OAuth的理解
  9. MySQL WorkBench中文教程
  10. EL(表达式语言)
  11. Map的遍历方法(java)
  12. .net prams关键字
  13. swap的实现(没有中间变量)
  14. hdu4607Park Visit 树的直径
  15. Quartz入门教程
  16. Redis分布式锁的实现
  17. (转)zabbix之生产案例
  18. EF Core中如何正确地设置两张表之间的关联关系
  19. TortoiseGit使用入门
  20. JavaScript中的对象冒充

热门文章

  1. 字符指针unsigned char *ch_p
  2. CF 8D two friends
  3. hdoj1257【疑问】(贪心)
  4. python实现希尔排序
  5. h5-20-文件操作-拖放文件
  6. java中常用到的math方法(Math.PI、Math.random()、Math.abs(double)、Math.floor(double)、Math.ceil(double)、Math.round(double))
  7. DNS递归查询、主从、加密认证、负载均衡
  8. Spark MLlib编程API入门系列之特征提取之主成分分析(PCA)
  9. 【前端】Html5浏览器缓存 sessionStorage 与 localStorage
  10. abp zero mysql版正式发布