CentOS 上使用 SQL Server 触发器的完整教程
一 环境准备与连接
- 在 CentOS 上安装并启动 Microsoft SQL Server,使用 sqlcmd 连接数据库:
- 安装工具与服务器(示例为 RHEL/CentOS 7 系列,其他版本请替换对应 repo):
- sudo yum install -y wget
- wget https://packages.microsoft.com/config/rhel/7/prod.list
- sudo tee /etc/yum.repos.d/mssql-release.repo
- sudo yum install -y msodbcsql17 unixodbc-devel mssql-server
- sudo systemctl start mssql-server
- sudo systemctl enable mssql-server
- 连接数据库(示例):
- 本地信任连接:sudo sqlcmd -S localhost -E
- 指定数据库:sudo sqlcmd -S localhost -d your_database -E
- 账号密码:sudo sqlcmd -S localhost -U sa -P ‘YourStrong@Passw0rd’
- 以上完成 SQL Server 在 Linux/CentOS 上的基本运行与连接准备。
二 触发器核心概念与语法
- 触发器类型与事件
- DML 触发器:响应表或视图上的 INSERT/UPDATE/DELETE;可用 AFTER(默认,FOR 同义)或 INSTEAD OF;视图仅支持 INSTEAD OF。同一表同一事件可定义多个 AFTER 触发器,可用 sp_settriggerorder 指定首个与末个;INSTEAD OF 每事件仅能有一个。触发器执行期间可使用两个逻辑表:inserted(新值)与 deleted(旧值)。
- 基本语法
- CREATE TRIGGER [schema.]trigger_name
ON { table | view }
{ FOR | AFTER | INSTEAD OF }
{ [INSERT] [,][UPDATE] [,][DELETE] }
[ WITH ]
AS { sql_statement [;] […] | EXTERNAL NAME }
- 常用要点
- AFTER:触发语句及约束检查都成功后执行;INSTEAD OF:替代原语句执行。
- 触发器内可访问 inserted/deleted 逻辑表进行条件判断与数据回写。
- 可用 IF UPDATE(column) 判断某列是否被更新(仅 INSERT/UPDATE 有效)。
三 实战示例
- 示例一 插入时自动写入时间戳
- 目标:向表插入数据时,自动填充 created_at / updated_at。
- 建表与触发器:
- CREATE TABLE dbo.products(
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(100),
price DECIMAL(10,2),
created_at DATETIME2,
updated_at DATETIME2
);
- GO
- CREATE TRIGGER trg_products_Insert
ON dbo.products
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE p
SET
created_at = GETDATE(),
updated_at = GETDATE()
FROM dbo.products AS p
JOIN inserted AS i ON i.id = p.id;
END
- GO
- 验证:
- INSERT INTO dbo.products(name, price) VALUES (N’笔记本’, 5999.00);
- SELECT id, name, price, created_at, updated_at FROM dbo.products;
- 示例二 更新审批状态并记录审计日志
- 目标:当 status 变更时写入审计表,若变为 2(已审批) 则回滚禁止审批。
- 建表与触发器:
-
CREATE TABLE dbo.orders(
id INT IDENTITY(1,1) PRIMARY KEY,
order_no NVARCHAR(50),
status TINYINT,
updated_at DATETIME2
);
-
CREATE TABLE dbo.orders_audit(
id INT IDENTITY(1,1) PRIMARY KEY,
order_id INT,
old_status TINYINT,
new_status TINYINT,
change_time DATETIME2
);
-
GO
-
CREATE TRIGGER trg_orders_StatusChange
ON dbo.orders
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
– 记录审计
INSERT INTO dbo.orders_audit(order_id, old_status, new_status, change_time)
SELECT
d.id,
d.status,
i.status,
GETDATE()
FROM deleted AS d
JOIN inserted AS i ON i.id = d.id
WHERE d.status <> i.status;
– 业务规则:已审批禁止再改回或变更
IF UPDATE(status)
BEGIN
IF EXISTS (
SELECT 1
FROM inserted AS i
JOIN deleted AS d ON d.id = i.id
WHERE d.status = 2 AND i.status <> 2
)
BEGIN
RAISERROR(‘已审批订单不允许变更状态。’, 16, 1);
ROLLBACK TRANSACTION;
RETURN;
END
END
END
-
GO
- 验证:
- INSERT INTO dbo.orders(order_no, status) VALUES (N’SO20251219001’, 1);
- UPDATE dbo.orders SET status = 2 WHERE order_no = N’SO20251219001’; – 成功
- UPDATE dbo.orders SET status = 1 WHERE order_no = N’SO20251219001’; – 触发回滚
- 示例三 软删除标记
- 目标:DELETE 时不真删,改为更新 is_deleted 与时间戳。
- 建表与触发器:
- CREATE TABLE dbo.customers(
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(100),
is_deleted BIT NOT NULL DEFAULT 0,
deleted_at DATETIME2 NULL
);
- GO
- CREATE TRIGGER trg_customers_SoftDelete
ON dbo.customers
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
UPDATE c
SET
is_deleted = 1,
deleted_at = GETDATE()
FROM dbo.customers AS c
JOIN deleted AS d ON d.id = c.id;
END
- GO
- 验证:
- INSERT INTO dbo.customers(name) VALUES (N’张三’);
- DELETE FROM dbo.customers WHERE name = N’张三’;
- SELECT id, name, is_deleted, deleted_at FROM dbo.customers;
- 说明
- 上述示例均使用 AFTER/INSTEAD OF、inserted/deleted、条件判断与 ROLLBACK 等常见模式,适合在 CentOS 上的 SQL Server 环境直接运行与验证。
四 管理与排错
- 常用管理语句
- 查看表上触发器:EXEC sp_helptrigger ‘schema.table’;
- 查看触发器定义:EXEC sp_helptext ‘schema.trigger_name’;
- 禁用/启用:DISABLE TRIGGER schema.trigger_name ON schema.table; / ENABLE TRIGGER schema.trigger_name ON schema.table;
- 删除:DROP TRIGGER IF EXISTS schema.trigger_name;
- 触发顺序:EXEC sp_settriggerorder
@triggername = ‘schema.trigger_name’,
@order = ‘First’ | ‘Last’,
@stmttype = ‘INSERT’ | ‘UPDATE’ | ‘DELETE’;
- 排错要点
- 触发器是依附于 DML 的自动过程,不能显式调用;逻辑在 inserted/deleted 中,注意多行影响与集合化处理,避免只取单行变量导致逻辑错误。
- 在触发器中如需阻止操作,使用 RAISERROR + ROLLBACK;注意事务与错误处理,避免“触发器中再触发”的无限递归(必要时控制触发顺序或改为 INSTEAD OF)。
- 性能建议:保持触发器逻辑轻量;只处理必要列;避免在触发器中执行远程/跨库调用;对大批量导入可临时禁用非关键触发器并在导入后补跑审计。