在Oracle数据库的实际应用中,经常会遇到需要将一张表的数据同步到另一张表,或者在源表发生数据变更时自动将变更内容复制到目标表的场景,存储过程和触发器是实现这类需求的核心工具。

存储过程实现数据复制
存储过程是预先编译好的一组SQL语句集合,我们可以编写存储过程,通过查询源表数据然后插入到目标表的方式完成数据复制,还可以添加条件过滤、批量处理等逻辑。
基础复制存储过程示例
假设我们有源表source_user和目标表target_user,表结构一致,都包含id、username、age三个字段,下面的存储过程会将源表中年龄大于18的用户数据复制到目标表:
CREATE OR REPLACE PROCEDURE copy_user_data AS
BEGIN
-- 清空目标表原有数据,可根据需求调整是否保留历史数据
DELETE FROM target_user;
-- 插入源表中符合条件的用户数据
INSERT INTO target_user (id, username, age)
SELECT id, username, age FROM source_user WHERE age > 18;
-- 提交事务
COMMIT;
DBMS_OUTPUT.PUT_LINE('数据复制完成');
EXCEPTION
WHEN OTHERS THEN
-- 出现异常时回滚事务
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('数据复制失败,错误原因:' || SQLERRM);
END copy_user_data;
调用存储过程
存储过程创建完成后,可以通过以下方式调用执行数据复制:
-- 调用存储过程
BEGIN
copy_user_data;
END;
触发器实现自动数据复制
触发器是当表发生特定事件(如插入、更新、删除)时自动执行的程序,我们可以为源表创建触发器,实现源表数据变更时自动将变更内容同步到目标表,不需要手动调用存储过程。
插入事件触发器示例
下面的触发器会在source_user表插入新数据时,自动将新数据同步到target_user表:
CREATE OR REPLACE TRIGGER sync_user_on_insert
AFTER INSERT ON source_user
FOR EACH ROW
BEGIN
-- 将新插入的数据同步到目标表
INSERT INTO target_user (id, username, age)
VALUES (:NEW.id, :NEW.username, :NEW.age);
END sync_user_on_insert;
更新事件触发器示例
如果还需要同步源表的更新操作,可以创建更新触发器:
CREATE OR REPLACE TRIGGER sync_user_on_update
AFTER UPDATE ON source_user
FOR EACH ROW
BEGIN
-- 更新目标表中对应id的数据
UPDATE target_user
SET username = :NEW.username,
age = :NEW.age
WHERE id = :OLD.id;
END sync_user_on_update;
删除事件触发器示例
如果需要同步删除操作,可创建删除触发器:
CREATE OR REPLACE TRIGGER sync_user_on_delete
AFTER DELETE ON source_user
FOR EACH ROW
BEGIN
-- 删除目标表中对应id的数据
DELETE FROM target_user WHERE id = :OLD.id;
END sync_user_on_delete;
两种方式的适用场景对比
存储过程和触发器各有适用场景,我们可以通过下表快速选择:
| 实现方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 存储过程 | 需要定时批量复制数据、一次性全量同步数据 | 逻辑灵活,可添加复杂过滤条件,执行时机可控 | 需要手动调用或配置定时任务,无法自动响应源表实时变更 |
| 触发器 | 需要源表数据变更时实时同步数据 | 自动执行,无需手动干预,实时性高 | 逻辑相对固定,过多触发器会影响源表操作性能 |
注意事项
- 使用存储过程复制数据时,要注意事务的控制,避免出现数据不一致的情况。
- 触发器会增加源表DML操作的开销,如果源表操作非常频繁,要谨慎使用触发器同步数据。
- 如果目标表需要保留历史数据,不要直接在存储过程中清空目标表,可添加时间戳字段区分不同批次的复制数据。
- 跨库复制数据时,需要配置数据库链接,触发器和存储过程中的表名要加上数据库链接后缀。