学习内容
- 什么是存储过程
- 如何使用存储过程
学习记录
存储过程
经常会有一个完整的操作需要多条语句才能完成。
此外,需要执行的具体语句及其次序也不是固定的,它们可能会根据条件而选择性的执行。
那应该怎么办呢?可以创建存储过程。
存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批文件(脚本?),虽然它们的作用不仅限于批处理。
- 执行存储过程
MySQL称存储过程的执行为调用,因此MySQL执行存储过程的语句为CALL。 CALL接受存储过程的名字以及需要传递给它的任意参数。
# 执行名为productpricing的存储过程,它计算并返回产品的最低、最高和平均价格
CALL productpricing(@pricelow,
@prichigh,
@priceaverage)
- 创建存储过程
此存储过程名为productpricing,用CREATE PROCEDURE productpricing()语句定义。如果存储过程接受参数,它们将在()中列举出来。此存储过程没有参数,但后跟的()仍然需要。
BEGIN和END语句用来限定存储过程体,过程体本身仅是一个简单的SELECT语句.。
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END;
上面出现了 多个分号分隔符,在命令行可能会出错
- 删除存储过程
# 此时的存储过程后面不需要带上括号了
DROP PROCEDURE productpricing;
- 使用参数
MySQL支持IN(传递给存储过程)、 OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。
# 这个存储过程接受一个参数 product_id,并返回与之对应的产品价格。
DELIMITER //
CREATE PROCEDURE productpricing(IN product_id INT)
BEGIN
SELECT price
FROM products
WHERE id = product_id;
END //
DELIMITER ;
如下这个存储过程接受一个参数 product_id,并返回与之对应的产品名称和价格。
在此例中,我们定义了两个输出参数:product_name 和 product_price。
当存储过程被调用时,这些参数将被填充为查询结果的值。这里使用了 INTO 关键字将查询结果赋值给输出参数。
DELIMITER //
CREATE PROCEDURE productpricing(IN product_id INT, OUT product_name VARCHAR(255), OUT product_price DECIMAL(10,2))
BEGIN
SELECT name, price INTO product_name, product_price
FROM products
WHERE id = product_id;
END //
DELIMITER ;
- 更复杂的存储过程
CREATE PROCEDURE calculate_order_total_with_tax(
IN order_id INT, -- 订单号
IN customer_state CHAR(2), -- 客户所在州
OUT order_total DECIMAL(10,2) -- 输出参数:合计(带税或不带税)
)
BEGIN
DECLARE subtotal DECIMAL(10,2); -- 小计
DECLARE tax_rate DECIMAL(4,2); -- 营业税率
DECLARE taxable_customer BOOLEAN; -- 是否需要添加营业税
SELECT SUM(price * quantity) INTO subtotal FROM order_items WHERE order_id = order_id; -- 计算小计
SELECT tax_rate INTO tax_rate FROM states WHERE state_code = customer_state; -- 获取客户所在州的营业税率
IF (tax_rate IS NOT NULL) THEN -- 如果该州有营业税
SELECT COUNT(*) INTO taxable_customer FROM customers WHERE state = customer_state; -- 检查顾客是否来自有税的州
IF (taxable_customer = 1) THEN -- 如果是有税的顾客
SET order_total = subtotal + (subtotal * tax_rate); -- 计算总合计(含税)
ELSE -- 如果是无税的顾客
SET order_total = subtotal; -- 总合计不含税
END IF;
ELSE -- 如果该州没有营业税
SET order_total = subtotal; -- 总合计不含税
END IF;
END;
sql版的脚本,没得一定经验搞不定。 ⇐ 暂时放弃!!
触发器
MySQL语句在需要时被执行,存储过程也是如此。但是,如果你想要某条语句(或某些语句)在事件发生时自动执行,怎么办呢?
触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):
- DELETE;
- INSERT;
- UPDATE。
触发器是针对数据库的,而不是针对服务器的。当特定事件在数据库中发生时,触发器会自动触发相应的操作或动作。这些操作可以是SQL语句、存储过程、或者其他类型的代码。触发器可以用来确保数据的一致性和完整性,以及执行其他需要在特定条件下自动执行的任务。
触发器是数据库对象的一种,因此记录在数据库中的系统表中。具体来说,在SQL Server数据库中,每个数据库都有一个名为sys.triggers的系统表,其中包含了所有触发器的信息。您可以使用SELECT语句从该表中检索有关触发器的详细信息,例如名称、创建日期、所属表等。此外,您也可以使用SQL Server Management Studio (SSMS) 或其他数据库管理工具来查看和管理触发器。
- 创建触发器
在创建触发器时,需要给出4条信息:
- 唯一的触发器名;
- 触发器关联的表;
- 触发器应该响应的活动( DELETE、 INSERT或UPDATE);
- 触发器何时执行(处理之前或之后)。
假设我们有一个名为 orders 的表,每当该表中插入新行时,我们需要自动更新 customers 表中对应客户的最近订单日期。
1.首先,在 MySQL 中创建一个名为 update_customer_last_order_date 的触发器:
CREATE TRIGGER update_customer_last_order_date
AFTER INSERT ON orders FOR EACH ROW
BEGIN
UPDATE customers
SET last_order_date = NEW.order_date
WHERE customer_id = NEW.customer_id;
END;
- AFTER INSERT ON orders 表示在 orders 表中插入新行后执行触发器。
- FOR EACH ROW 表示对于每个插入的行都执行一次该触发器。
- NEW 表示新插入的行,我们可以使用 NEW. 来访问其列值。
- UPDATE customers SET last_order_date = NEW.order_date 表示将 customers 表中 last_order_date 列更新为新插入的 orders 表中的 order_date 值。
- WHERE customer_id = NEW.customer_id 表示仅更新与新插入行相应的客户记录。
- 删除触发器
触发器不能更新或覆盖。为了修改一个触发器,必须先删除它,然后再重新创建
DROP TRIGGER newtrigger;
事务处理
事务处理是一种机制,用来管理必须成批执行的MySQL操作,以保证数据库不包含不完整的操作结果。
利用事务处理,可以保证一组操作不会中途停止,它们或者作为整体执行,或者完全不执行(除非明确指示)。如果没有错误发 生,整组语句提交给(写到)数据库表。如果发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。
简单来说,事务处理(transaction processing)可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行。
下面是关于事务处理需要知道的几个术语:
- 事务(transaction)指一组SQL语句;
- 回退(rollback)指撤销指定SQL语句的过程;
- 提交(commit)指将未存储的SQL语句结果写入数据库表;
- 保留点( savepoint)指事务处理中设置的临时占位符( placeholder),你可以对它发布回退(与回退整个事务处理不同)。
管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
- ROLLBACK
例如,首先执行一条SELECT以显示该表不为空。
然后开始一个事务处理,用一条DELETE语句删除ordertotals中的所有行。
另一条SELECT语句验证ordertotals确实为空。
这时用一条ROLLBACK语句回退START TRANSACTION之后的所有语句,最后一条SELECT语句显示该表不为空。
SELECT * FROM ordertotals;
START TRANSACTION;
DELETE FROM ordertotal;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;
-
COMMIT
一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交( implicit commit),即提交(写或保存)操作是自动进行的。但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用COMMIT语句.
START TRANSACTION
DELETE XXX,
DELETE XXX,
COMMIT;
- 保留点
为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。这样,如果需要回退,可以回退到某个占位符。
这些占位符称为保留点。为了创建占位符,可如下使用SAVEPOINT语句。
# 每个保留点都取标识它的唯一名字,以便在回退时, MySQL知道要回退到何处
SAVEPOINT delete1;
# 为了回退到本例给出的保留点,可如下进行
ROLLBACK TO delete1;
-
更改默认提交行为
默认的MySQL行为是自动提交所有更改。换句话说,任何时候你执行一条MySQL语句,该语句实际上都是针对表执行的,而且所做的更改立即生效。为指示MySQL不自动提交更改,需要使用以下语句:
SET auotcommit = 0;