SQL触发器(Trigger)是一种特殊的存储过程,它会在特定事件(如INSERT、UPDATE或DELETE)发生时自动执行。触发器与表直接关联,当表数据发生变化时自动触发执行。
DML触发器:响应数据操作语言(DML)事件
DDL触发器:响应数据定义语言(DDL)事件
登录触发器:响应登录事件
CREATE TRIGGER trigger_name
ON table_name
[AFTER|BEFORE|INSTEAD OF] [INSERT|UPDATE|DELETE]
AS
BEGIN
-- 触发器逻辑代码
END
数据完整性验证:在数据修改前进行验证
CREATE TRIGGER tr_CheckSalary
ON Employees
AFTER INSERT, UPDATE
AS
BEGIN
IF EXISTS (SELECT 1 FROM inserted WHERE Salary < 0)
BEGIN
RAISERROR('薪资不能为负数', 16, 1)
ROLLBACK TRANSACTION
END
END
审计跟踪:记录数据变更历史
CREATE TRIGGER tr_AuditEmployeeChanges
ON Employees
AFTER UPDATE, DELETE
AS
BEGIN
INSERT INTO EmployeeAudit(EmployeeID, ChangeType, ChangeDate, OldData, NewData)
SELECT
d.EmployeeID,
CASE WHEN d.EmployeeID IS NOT NULL AND i.EmployeeID IS NOT NULL THEN 'UPDATE'
WHEN d.EmployeeID IS NOT NULL THEN 'DELETE'
END,
GETDATE(),
(SELECT * FROM deleted FOR JSON PATH),
(SELECT * FROM inserted FOR JSON PATH)
FROM deleted d
LEFT JOIN inserted i ON d.EmployeeID = i.EmployeeID
END
级联操作:自动更新相关表数据
CREATE TRIGGER tr_UpdateOrderTotal
ON OrderDetails
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
UPDATE o
SET o.TotalAmount = (SELECT SUM(Quantity * UnitPrice) FROM OrderDetails WHERE OrderID = o.OrderID)
FROM Orders o
JOIN inserted i ON o.OrderID = i.OrderID
END
数据同步:保持多个表数据一致
CREATE TRIGGER tr_SyncInventory
ON Products
AFTER INSERT
AS
BEGIN
INSERT INTO Inventory(ProductID, Quantity)
SELECT ProductID, 0 FROM inserted
END
特性 | 触发器 | 存储过程 |
---|---|---|
执行方式 | 自动触发 | 显式调用 |
参数 | 无直接参数,通过inserted/deleted表访问 | 可以有输入/输出参数 |
返回值 | 无 | 可以有返回值 |
事务上下文 | 在触发操作的事务中执行 | 可以独立事务或参与调用者事务 |
主要用途 | 数据变更时自动执行逻辑 | 封装可重用业务逻辑 |
嵌套触发器:一个触发器可以触发另一个触发器
使用UPDATE()函数:检测特定列是否被更新
IF UPDATE(Salary)
BEGIN
-- 薪资字段被修改时的逻辑
END
处理多行操作:触发器应能处理影响多行的操作
-- 错误示例:假设只处理单行
DECLARE @newValue int = (SELECT Column1 FROM inserted)
-- 正确示例:处理多行
INSERT INTO AuditTable
SELECT Column1, GETDATE() FROM inserted
禁用/启用触发器:临时控制触发器执行
-- 禁用触发器
DISABLE TRIGGER tr_MyTrigger ON MyTable
-- 启用触发器
ENABLE TRIGGER tr_MyTrigger ON MyTable
SQL Server:
MySQL:
Oracle:
PostgreSQL:
CREATE TRIGGER tr_OrderStatusNotification
ON Orders
AFTER UPDATE
AS
BEGIN
-- 仅当状态字段变更时执行
IF UPDATE(Status)
BEGIN
-- 获取状态变更的订单
INSERT INTO Notifications(OrderID, CustomerID, OldStatus, NewStatus, NotificationDate)
SELECT
i.OrderID,
i.CustomerID,
d.Status AS OldStatus,
i.Status AS NewStatus,
GETDATE()
FROM inserted i
JOIN deleted d ON i.OrderID = d.OrderID
WHERE i.Status <> d.Status
-- 对于已发货的订单,更新库存
UPDATE p
SET p.StockQuantity = p.StockQuantity - od.Quantity
FROM Products p
JOIN OrderDetails od ON p.ProductID = od.ProductID
JOIN inserted i ON od.OrderID = i.OrderID
WHERE i.Status = 'Shipped' AND
EXISTS (SELECT 1 FROM deleted d WHERE d.OrderID = i.OrderID AND d.Status <> 'Shipped')
END
END
SQL触发器是数据库自动化任务的强大工具,可以确保数据一致性、实现审计跟踪、执行业务规则等。合理使用触发器可以显著减少应用层代码的复杂性,但过度使用也可能导致维护困难和性能问题。在设计触发器时,应充分考虑其必要性、性能影响和维护成本,遵循最佳实践来构建高效可靠的数据库自动化解决方案。