【回顾MySQL的SQL基础开发与应用】SQL分类与数据类型、视图、触发器以及存储过程与事件

⚡⚡⚡ 新年新文⚡⚡⚡


文章目录


1,MySQL的SQL分类与数据类型

1.1,SQL分类

SQL(发音为字母S-Q-L或sequel)的英文全称为Structured Query Language,SQL用来和数据库打交道,完成和数据库的通信。SQL是一套标准,但是每一个数据库都有自己的特性,当使用与这个数据库特性相关的功能,这时SQL语句可能就不是标准了,但是百分之九十以上的SQL都是通用的。SQL语句分为DQL、DML、DDL、DCL和TCL五大类。

  • DDL
    数据定义语言(Data Definition Language,简称DDL):DDL用于定义数据库的结构,包括创建、修改和删除数据库、表、索引、视图等元素。常用的DDL语句包括CREATE、ALTER和DROP。
  • DML
    数据操作语言(Data Manipulation Language,简称DML):DML用于对数据库中的数据进行操作,包括插入、更新和删除数据。常用的DML语句包括SELECT、INSERT、UPDATE和DELETE。
  • DCL
    数据控制语言(Data Control Language,简称DCL):DCL用于控制数据库中数据的访问权限和数据完整性的约束,包括授权和回收权限、创建用户和角色等。常用的DCL语句包括GRANT和REVOKE。
  • TCL
    事务控制语言(Transaction Control Language,简称TCL):TCL用于控制事务的提交和回滚,保证数据库的一致性和完整性。常用的TCL语句包括COMMIT和ROLLBACK。
  • DQL
    数据查询语言(Data Query Language,简称DQL):DQL用于从数据库中获取数据,进行数据的查询和检索。常用的DQL语句是SELECT。

1.2,MySQL数据类型

在MySQL中,常见的数据类型包括数值型、字符串型、二进制型、日期型和其他类型。

  • 数值型
    MySQL支持多种数值型数据类型,包括整数型、小数型和布尔型。
  • 整数型
    TINYINT:1字节,取值范围为-128到127或0到255。
    SMALLINT:2字节,取值范围为-32768到32767或0到65535。
    MEDIUMINT:3字节,取值范围为-8388608到8388607或0到16777215。
    INT:4字节,取值范围为-2147483648到2147483647或0到4294967295。
    BIGINT:8字节,取值范围为-9223372036854775808到9223372036854775807或0到18446744073709551615。
  • 小数型
    FLOAT:4字节,单精度浮点数,精度为7位。
    DOUBLE:8字节,双精度浮点数,精度为15位。
    DECIMAL:可变长度,用于存储精确的小数,精度和数据长度可以自定义。
  • 布尔型
    MySQL支持布尔型数据类型,即BOOLEAN或BOOL。它只占用1位,取值为TRUE或FALSE。
  • 日期型
    DATE:用于存储日期,格式为YYYY-MM-DD。
    TIME:用于存储时间,格式为HH:MM:SS。
    DATETIME:用于存储日期时间,格式为YYYY-MM-DD HH:MM:SS。
    TIMESTAMP:用于存储时间戳,格式为YYYY-MM-DD HH:MM:SS。
    YEAR:用于存储年份,格式为YYYY。
  • 字符串型
    CHAR:用于存储固定长度的字符串,长度为0到255个字符。
    VARCHAR:用于存储可变长度的字符串,长度为0到65535个字符。
    TEXT:用于存储大量的文本数据,最大长度为65535个字符。
    BLOB:用于存储大量的二进制数据,最大长度为65535个字节。
    ENUM:用于存储枚举类型的数据,如性别、状态等。
  • 二进制型
    BIT:用于存储比特位,长度为1到64个比特位。
    BINARY:用于存储固定长度的二进制数据,长度为0到255个字节。
    VARBINARY:用于存储可变长度的二进制数据,长度为0到65535个字节。
  • 其他类型
    SET:用于存储一组可选值,最多可以有64个选项。
    JSON:用于存储JSON格式的数据。
    Geometry:用于存储几何类型的数据,如点、线、面等。

2,MySQL的视图

不需要关心后面对应的表的结构、关联条件和筛选条件,查询已经过滤好的复合条件的结果集;

视图不光能简化查询还能允许查询某些数据提高了安全性;看看下面写的每种数最高价格且大于25并排序:

sql 复制代码
CREATE VIEW `v_booktype_maxprice`
AS 
SELECT `bt`.`book_type`,MAX( `b`.`price` ) 
FROM `books` AS `b`
  LEFT JOIN `book_types` AS `bt` ON `b`.`type_id` = `bt`.`type_id` 
GROUP BY `b`.`type_id` 
HAVING MAX( `b`.`price` ) > 25 
ORDER BY MAX( `b`.`price` ) DESC 
LIMIT 10;
  • 当视图被创建之后,则其定义就已经固定不会再改变,比如一个视图是由select *创建的,则后续对表增加的字段不会成为视图的一部分,而后续对表删除字段则会导致查询视图失败。
  • 创建的视图默认情况下是属于当前数据库的,当要创建到另外的数据库时则需要在视图名前面加上数据库名。
  • 一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列名对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。
sql 复制代码
SELECT * FROM `v_booktype_maxprice`;

要查22元以上的,还能用语句ALTER VIEW用来修改视图的定义,如下:

sql 复制代码
ALTER VIEW `v_booktype_maxprice`
AS 
SELECT `bt`.`book_type`,MAX( `b`.`price` ) 
FROM `books` AS `b`
  LEFT JOIN `book_types` AS `bt` ON `b`.`type_id` = `bt`.`type_id` 
GROUP BY `b`.`type_id` 
HAVING MAX( `b`.`price` ) > 22 
ORDER BY MAX( `b`.`price` ) DESC 
LIMIT 10;

SQL查询goods库里有哪些视图:

sql 复制代码
SELECT `TABLE_NAME` 
FROM `information_schema`.`VIEWS` 
WHERE `TABLE_SCHEMA`='goods';

SQL查看视图详情。

sql 复制代码
SHOW CREATE VIEW `goods`.`v_booktype_maxprice`\G

SQL删除视图

sql 复制代码
DROP VIEW IF EXISTS `goods`.`v_booktype_maxprice`;

3,MySQL数据库触发器

3.1,需求说明

当客户购买书时,书的库存量会根据订单购买的数量的变化而变化,如果某个表中的数据发生变化时需要自动执行一组SQL,可以为该表创建一个触发器。

我们先给books表增加一个库存列,再创建订单表和用户表并插入数据。

sql 复制代码
SET NAMES utf8;
-- ----------------------------
-- 给books表增加一个库存列
-- ----------------------------
ALTER TABLE `books` ADD COLUMN `stock` BIGINT UNSIGNED  NOT NULL DEFAULT 1000 COMMENT '库存量' AFTER `price`;

SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- 创建用户表
-- ----------------------------
CREATE TABLE IF NOT EXISTS `users` (
  `user_id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名称',
  `register_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户注册时间',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- 创建订单表
-- ----------------------------
CREATE TABLE IF NOT EXISTS `orders` (
  `order_id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID',
  `user_id` bigint unsigned NOT NULL COMMENT '用户ID',
  `order_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '订单时间',
  PRIMARY KEY (`order_id`),
  KEY `fk_user_id_idx` (`user_id`),
  CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- 创建订单详情表
-- ----------------------------
CREATE TABLE IF NOT EXISTS `order_items` (
  `order_item_id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '订单项目ID',
  `order_id` bigint unsigned NOT NULL COMMENT '订单ID',
  `book_id` bigint unsigned NOT NULL COMMENT '书籍ID',
  `quantity` int unsigned NOT NULL COMMENT '商品数量',
  PRIMARY KEY (`order_item_id`),
  KEY `fk_order_id` (`order_id`),
  KEY `fk_book_id` (`book_id`),
  CONSTRAINT `fk_book_id` FOREIGN KEY (`book_id`) REFERENCES `books` (`book_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_order_id` FOREIGN KEY (`order_id`) REFERENCES `orders` (`order_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;


-- ----------------------------
-- 注册新用户
-- ----------------------------
INSERT INTO `users` (`user_name`)
VALUES('Alice'),('Bob'),('Charlie'),('David'),('Eve');

说明:因为有外键约束建表有依赖关系,因此我们用SET FOREIGN_KEY_CHECKS=0关闭外键检查,建好表之后再打开即可。

3.2,触发器使用

一个触发器会监听一张表,当对该表进行INSERT、UPDATE或DELETE操作时,则触发执行一组SQL。

触发器创建语法四要素:

  • 监视地点(table)
  • 监视事件(INSERT/UPDATE/DELETE)
  • 触发时间(BEFORE/AFTER)
  • 触发事件(INSERT/UPDATE/DELETE)。

用户对订单有增加 、删除和修改动作,因此创建三个触发器。

sql 复制代码
-- ----------------------------
-- 用户下单
-- ----------------------------
CREATE TRIGGER tg_insert_o
AFTER INSERT
ON order_items FOR EACH ROW
UPDATE `books` SET `stock`=`stock`-new.`quantity` WHERE `book_id`=new.`book_id`;

-- ----------------------------
-- 用户修改订单
-- ----------------------------
CREATE TRIGGER tg_update_o
AFTER UPDATE
ON order_items FOR EACH ROW
UPDATE `books` SET `stock`=old.`quantity`-new.`quantity`+`stock` WHERE `book_id`=old.`book_id`;

-- ----------------------------
-- 用户退订单
-- ----------------------------
CREATE TRIGGER tg_delete_o
AFTER DELETE
ON order_items FOR EACH ROW
UPDATE `books` SET `stock`=`stock`+old.`quantity` WHERE `book_id`=old.`book_id`;
  • BEFORE和AFTER指定触发器在表中的每行数据修改前或者后执行。
  • old.col_quantity表示行数据被修改或删除之前的字段数据,new.quantity表示行数据被插入或修改之后的字段数据。变化量 = 修改前的量(old.quantity) -- 修改后的量(new.quantity)
  • 当该表删除时,触发器也自动删除了。

假如Bob下单购买了1本《人类简史》、8本《三体》和2本《围城》,需要先查出对应的ID再插入。

sql 复制代码
INSERT INTO `orders`(`user_id`) VALUE(2);
INSERT INTO `order_items`(`order_id`,`book_id`,`quantity`)  VALUES(1,3,1),(1,7,8),(1,8,2);

看books表中的《人类简史》、《三体》和《围城》的库存各少了1、8和2本。

当用户修改订单《三体》只买5本时,执行如下SQL:

sql 复制代码
UPDATE `order_items` SET `quantity`=5 WHERE `order_item_id`=2;

看books表中的《三体》库存多了3本,符合预期。

当用户决定不买《围城》了,在订单中把该书删掉:

sql 复制代码
DELETE FROM `order_items` WHERE `order_item_id`=3;

books表《围城》库存多了2本,符合预期。当我新接手一个库,我怎么查看库里的触发器呢?

可以用下面SQL查询goods库里有哪些触发器。

sql 复制代码
select trigger_name from information_schema.triggers where event_object_schema='goods';

再根据下面的SQL查看触发器详情。

sql 复制代码
show create trigger tg_update_o\G

如果这个触发器不用了,用下面SQL删除呢

sql 复制代码
DROP TRIGGER IF EXISTS `goods`.`tg_delete_o`;

4,MySQL的存储过程与事件

4.1,需求说明

业务那边需要每天早上9点统计昨天用户增长量,需要先算截止到前天用户数和昨天的用户总数相减,这样一组SQL集合就可以用存储过程。

4.2,存储过程的使用

写一个存储过程,实现这个需求。

sql 复制代码
DELIMITER //
CREATE PROCEDURE sp_user_growth()
BEGIN
  DECLARE today DATE;
  DECLARE yesterday DATE;
  DECLARE usercount_yesterday INT UNSIGNED DEFAULT 0;
  DECLARE usercount_yesterdaybefore INT UNSIGNED DEFAULT 0;
  
  SELECT CURDATE() INTO today;
  SELECT DATE_SUB(CURDATE(), INTERVAL 1 DAY) INTO yesterday;
  
  SELECT COUNT(*) FROM `users` WHERE register_time<today INTO usercount_yesterday;  -- 昨天用户总数
  SELECT COUNT(*) FROM `users` WHERE register_time<yesterday INTO usercount_yesterdaybefore;  -- 前天用户总数
  
  SELECT usercount_yesterday - usercount_yesterdaybefore AS '昨天用户新增';
END //  

DELIMITER ;
  • MySQL结束符默认是分号,此时普通SQL与存储过程的结束符就会混淆导致语句无法执行,因此用DELIMITER改变语句的结束符。
  • 存储过程BEGIN...END其中可以包含一个或多个语句,每个语句用 ; 隔开。
  • DECLARE语句通常用来声明变量;声明后的变量可以通过SELECT ... INTO进行赋值。

创建好存储过程后,以后只要通过CALL命令来调用存储过程即可得到结果。

sql 复制代码
CALL sp_user_growth();

SQL删除存储过程

sql 复制代码
DROP PROCEDURE IF EXISTS sp_user_growth

每天早上9点出结果

sql 复制代码
DELIMITER //
CREATE EVENT callSpusergrowthJob 
ON SCHEDULE EVERY 1 DAY
STARTS DATE_ADD(CURDATE(), INTERVAL 9 HOUR)
ON COMPLETION PRESERVE
COMMENT '每天早上9点调用统计昨日用户增长存储过程'
DO BEGIN
  CALL sp_user_growth();
END //
DELIMITER ;
  • ON SCHEDULE:计划任务。
  • COMMENT:可选项用来描述event;相当注释,最大长度64个字节。
  • ON COMPLETION PRESERVE: 可选项,默认是ON COMPLETION NOT PRESERVE 即计划任务执行完毕后自动drop该事件;ON COMPLETION PRESERVE则不会drop掉。

通过下面这个命令可以查看当前所在库的事件。

sql 复制代码
SHOW EVENTS\G

要想使Events生效,还需要开启事件调度器:

sql 复制代码
SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler = ON;

说明:使用SET GLOBAL的方式设置参数需要客户端重连mysql服务,并且在mysql服务重启后失效,要想在mysql服务重启后永久生效需要修改mysql配置文件。

SQL删除事件

sql 复制代码
DROP EVENT IF EXISTS callSpusergrowthJob;

存储过程虽然很方便、安全性也还不错,但是MySQL的存储过程缺乏debug功能,维护起来成本很高,因此在后端开发中,能用程序解决的尽量不要用存储过程。


感谢阅读,下期更精彩 👋👋👋

相关推荐
Howie Zphile1 小时前
FRAPPE v16 +postgresql +insight+wiki安装
数据库·postgresql·frappe·全面预算
枷锁—sha1 小时前
【SRC】SSRF (服务端请求伪造) 专项挖掘与实战笔记
数据库·笔记·安全·网络安全
知识分享小能手2 小时前
SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019 触发器 — 语法知识点及使用方法详解(17)
数据库·学习·sqlserver
tod1132 小时前
Redis Sentinel 高可用架构:从原理到 Docker 部署全解析
数据库·redis·docker·架构·sentinel
014-code2 小时前
Redis 是如何实现与数据库的一致性呢?
数据库·redis·缓存
清水白石0082 小时前
缓存的艺术:Python 高性能编程中的策略选择与全景实战
开发语言·数据库·python
AI Echoes2 小时前
对接自定义向量数据库的配置与使用
数据库·人工智能·python·langchain·prompt·agent
专注VB编程开发20年2 小时前
多线程,CS多台电脑redis扣款不出错方案
数据库·redis·缓存