SQL 进阶(视图,事件,事务,触发器,存储过程)

SQL进阶学习

视图

我们有时候需要经常性的需要一些查询结果,快速它的查询过程极为繁琐,这种情况下可以采用视图将结果进行保存。再下一次查询的时候只需要查询视图即可。

视图不存储数据,他只是数据的搬运工。因此数据表中数据的更新也会使视图中的数据更新。

视图创建

我们来将每一个顾客的收支情况存入视图。

CREATE VIEW clients_balance AS 
   SELECT c.client_id,c.name,SUM(invoice_total-payment_total) AS balance
   FROM clients c
   JOIN invoices i USING (client_id)
   GROUP BY client_id,NAME;

视图查询

属性查询
DESCRIBE clients_balance;
--简写
DESC clients_balance;
数据查询
select * from clients_balance;

视图修改

我们可以通过修改视图来重新构建/获取视图,OR REPLACE关键词可以做到。

CREATE OR REPLACE VIEW clients_balance AS 
   SELECT c.client_id,c.name,SUM(invoice_total-payment_total) AS balance
   FROM clients c
   JOIN invoices i USING (client_id)
   GROUP BY client_id,NAME;

视图删除

DROP VIEW clients_balance;

DROP VIEW IF EXISTS clients_balance;

可更新视图

有时候我们没有对数据表的数据进行增删改的操作权限,但是我们又需要有这样的业务。那么我们可以通过创建一个可更新视图来完成这样的操作。

可更新视图有以下几个特点:

  1. 视图中不含有DICTINCT函数。
  2. 视图中没有聚合函数(MAX/MIN/SUM)等等。
  3. 视图中不含有GROUP BY等分组。
  4. 视图中不含有UNION联合查询。

满足上述条件我们就可以对他进行增删改,结构和在数据表中的操作差不多。

注意在视图中的更新也会在数据表中更新,也就是说视图中删除了,原表中也将会删除数据。

--增加
INSERT INTO clients_view VALUE(6,'wang')
--修改
update clients_view set name='wnag'
where id=1;
--删除
DELETE FROM clients_view
WHERE NAME='zhang'

WITH CHECk OPTION

我们在更新视图的查询过程,可能会减少一些行,有时候我们并不想要减少这些行,可以通过WITH CHECR OPTION关键词来获取这些行。

CREATE OR REPLACE VIEW clients_balance AS 
   SELECT invoice_id,
   invoice_total,
   payment_total,
   invoice_total-payment_total AS balance
   FROM invoices
   WHERE (invoice_total-payment_total)>0
WITH CHECK OPTION;

然后我们在视图中寻找一行,更新该行的payment_total使balance值为0,看看该行会不会消失。

UPDATE clients_balance
SET payment_total = invoice_total
WHERE invoice_id=3

此时会报错,提示检查视图失败,通过这种方式我们可以避免视图中的数据丢失。

视图的优点

  1. 简化查询。
  2. 减少数据表改变带来的影响。
  3. 限制用户对数据的访问。

存储过程

我们知道在开发过程中,我们不仅仅需要一门语言,SQL仅仅是数据存储中使用的一门语言。我们不想在其它地方使用它,比如JAVA的代码中,那会使我们很难部署并且调试我们的代码。

我觉得存储过程就是一个面向对象的设计,把数据的管理通过存储过程来实现,可以增强数据的安全性。

创建存储过程

CREATE PROCEDURE get_client()
BEGIN
   SELECT * FROM clients;
END 

在除了MySQL数据库以外的地方这样写好像没有什么问题,但是MySQL中需要更换写法。因为SQL的语法需要在select以后加一个分号,但是我们的语句是到END才结束。所以需要改变分隔符。

DEFINER

定义该存储过程是是写的,如果没有写,默认为创建者。

DELIMITER $$
CREATE DEFINER `root`@`localhost` PROCEDURE get_client()
BEGIN
   SELECT * FROM clients;
END$$
DELIMITER ;

DELIMITER

DELIMITER可以更改分隔符。

DELIMITER $$
CREATE PROCEDURE get_client()
BEGIN
   SELECT * FROM clients;
END$$
DELIMITER ;

SQL中调用存储过程

CALL get_client();

删除数据库

DROP PROCEDURE get_clients;

DROP PROCEDURE IF EXISTS get_clients;

带参数的存储过程

为了保证起的名字不一样,我喜欢用给数据表起别名的方式来进行区分,多个参数用,逗号分隔即可。

也有一些大佬喜欢更改参数名称,请自便。

DELIMITER $$
CREATE PROCEDURE get_client_by_id(client_id INT(11))
BEGIN
   SELECT * FROM clients c
   WHERE c.client_id=client_id;
END$$
DELIMITER ;

CALL get_client_by_id(1);

给参数默认值的存储过程

其实就是IF语句的使用

DROP PROCEDURE IF EXISTS get_client_by_id;
DELIMITER $$
CREATE PROCEDURE get_client_by_id(client_id INT(11))
BEGIN
   IF client_id IS NULL THEN 
      SET client_id=1;
   END IF;
   SELECT * FROM clients c
   WHERE c.client_id=client_id;
END$$
DELIMITER ;

CALL get_client_by_id(NULL);

当然我们也可以使用IFNULL,注意SQL server可能使用的是ISNULL

DROP PROCEDURE IF EXISTS get_client_by_id;
DELIMITER $$
CREATE PROCEDURE get_client_by_id(client_id INT(11))
BEGIN
   SELECT * FROM clients c
   WHERE c.client_id=IFNULL(client_id,c.client_id);
END$$
DELIMITER ;

CALL get_client_by_id(NULL);

参数校验

SIGNAL SQLSTATE去获取错误编码,SET MESSAGE_TEXT写入错误信息。

关于错误编码的事情网上搜SQL STATE就有很多,我就不列举了。

下列例子对编号小于等于0的进行了验证:

DROP PROCEDURE IF EXISTS get_client_by_id;
DELIMITER $$
CREATE PROCEDURE get_client_by_id(client_id INT(11))
BEGIN
   IF client_id<=0 THEN
      SIGNAL SQLSTATE '22003'
        SET MESSAGE_TEXT = 'Invalid payment amount';
   END IF;
   SELECT * FROM clients c
   WHERE c.client_id=client_id;
END$$
DELIMITER ;

CALL get_client_by_id(-1);

存储过程输出

OUT关键字。

DROP PROCEDURE IF EXISTS get_client_by_id;
DELIMITER $$
CREATE PROCEDURE get_client_by_id(
client_id INT,
OUT p_name VARCHAR(50))
BEGIN
   SELECT c.name 
   INTO p_name--输出的名字
   FROM clients c
   WHERE c.client_id=IFNULL(client_id,c.client_id);
END$$
DELIMITER ;

SET @NAME = '';
CALL get_client_by_id(NULL,@NAME);
SELECT @NAME;

关于存储过程的输出,我个人觉得其实没有那么好用,也不建议使用。

变量

直接赋值,相当于全局变量,作用域为当前整个事务。

SET @w=2;
SELECT @w;
DECLARE

主要用于存储过程中:

DECLARE var1 INT DEFAULT 0; 

函数

DETERMINISTIC–保证输入数据一样时输出结果不变
READS SQL DATA --保证可以读取数据
MODIFIES SQL DATA–保证可以修改数据

DROP FUNCTION IF EXISTS get_name;
DELIMITER $$
CREATE FUNCTION get_name(client_id INT) 
RETURNS VARCHAR(50)
BEGIN
   DECLARE a VARCHAR(50);
   SELECT c.name
   INTO a FROM clients c WHERE c.client_id=client_id;
   RETURN a;
END$$
DELIMITER ;

SELECT get_name(1);

触发器

创建触发器

DELIMITER $$
CREATE TRIGGER payments_after_delete
   AFTER DELETE ON payments
   FOR EACH ROW
BEGIN
   UPDATE invoices
   SET payment_total=payment_total -OLD.amount
   WHERE invoice_id = old.invoice_id;
END $$
DELIMITER ;

DELETE FROM payments WHERE payment_id=8;

查询触发器

SHOW TRIGGERS;
--模糊查询
SHOW TRIGGERS LIKE 'payments%';

删除触发器

DROP TRIGGER IF EXISTS payments_after_delete;

事件

先在sql变量表中查询所有的变量信息,找到并打开事件系统。

--找到
SHOW VARIABLES LIKE 'event%';
--打开
SET GLOBAL event_scheduler = ON;

创建事件

DELIMITER $$
CREATE event yearly_delete_stale_audit_rows
ON SCHEDULE
   --只执行一次
   at ''
   --周期执行
   EVERY 1 YEAR STARTS '2020-01-01' ENDS '2021-01-02'
DO BEGIN
   DELETE FROM payments_audit
   WHERE action_date<NOW()-INTERVAL 1 YEAR;
END $$
DELIMITER ;

查询事件

SHOW EVENTS;
 
SHOW EVENTS IF EXISTS yearly_delete_stale_audit_rows;

修改事件

我们只需要把CREATE改为ALTER即可。

当然如果是开始或关闭该事件我们可以通过:

--enable开启事件
ALTER event yearly_delete_stale_audit_rows DISABLE;--暂停事件

删除事件

DROP EVENTS yearly_delete_stale_audit_rows;

DROP EVENTS IF EXISTS yearly_delete_stale_audit_rows

事务

事务的属性

事务的属性可以用ACID来概括。也就是原子性atomicity,一致性consistency,隔离性isolation,持久性durability。换而言之就是保证该事务能够不受外界干扰的执行,并且结果可以持久保持的性质。

事务的创建

MySQL自带的有一个事务的情况,当我们的增删改操作在使用的时候,会自动加入事务,这样一行数据的更新即为一个事务。

SHOW VARIABLES LIKE 'autocommit%';

查到后发现默认开启状态。

那么我们有时候需要对于多行进行操作并且保证在一个事务里边:

START TRANSACTION;事务的开始,COMMIT事务的提交。

USE sql_store;
START TRANSACTION;
INSERT INTO orders(customer_id,order_date,STATUS)
VALUE(1,'2021-01-01',1);
INSERT INTO orders_item
VALUE(LAST_INSERT_ID(),1,1,1);
COMMIT;

有时候我们会人为的想取消该事务并且不让该事务对数据造成影响使用回滚ROLLBACK,去关闭事务并撤销所有更改。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值