-- 同步模板关键点
CREATE OR REPLACE PROCEDURE SYNC_DATA IS
-- 1. 分批参数
C_BATCH_SIZE CONSTANT NUMBER := 10000;
V_LAST_ID NUMBER := 0;
V_BATCH_COUNT NUMBER := 0;
BEGIN
LOOP
-- 2. 批量收集 + 分批提交
FORALL I IN 1..V_BATCH.COUNT SAVING EXCEPTIONS -- 单行异常隔离
MERGE INTO TARGET T USING SOURCE S ON (T.ID = S.ID)
WHEN MATCHED THEN UPDATE ...
WHEN NOT MATCHED THEN INSERT ...;
-- 3. 每批提交
COMMIT;
V_BATCH_COUNT := V_BATCH_COUNT + 1;
EXIT WHEN V_BATCH.COUNT < C_BATCH_SIZE;
END LOOP;
-- 4. 更新统计信息
DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'TARGET');
EXCEPTION
WHEN OTHERS THEN
-- 5. 异常回滚 + 记录错误行
ROLLBACK;
INSERT INTO SYNC_ERROR_LOG VALUES (SQLCODE, SQLERRM, SYSDATE);
COMMIT;
RAISE;
END;
八、快速检查清单(数据同步前核对)
检查项
是否确认
✓ 目标表结构是否与源表匹配(字段数、类型、长度)
☐
✓ NOT NULL 字段是否有默认值或源表有值
☐
✓ 主键/唯一约束是否会导致冲突
☐
✓ 外键依赖数据是否已存在
☐
✓ 同步期间是否禁用触发器/索引(全量时)
☐
✓ 是否有可靠的增量字段(增量同步时)
☐
✓ 分批提交大小是否合理(1000-10000)
☐
✓ 异常数据是否记录到错误表
☐
✓ 同步后是否比对数据量/校验和
☐
✓ 是否准备好回滚方案
☐
源表和目标表的字段数量,字段命名是否要一致?
核心答案:不一定需要一致,但有不同场景的最佳实践。
一、快速结论表
维度
是否需要一致
说明
字段数量
❌ 不需要
目标表可以多字段或少字段
字段命名
❌ 不需要
可以通过映射关系转换
字段类型
⚠️ 必须兼容
源表类型必须能隐式/显式转换为目标表类型
字段顺序
❌ 不需要
SELECT 时按目标表顺序显式指定即可
二、不同场景的处理方式
场景1:字段数量不一致
情况
处理方式
示例
目标表字段 少 于源表
只 SELECT 需要的字段,多余字段丢弃
INSERT INTO TARGET(ID, NAME) SELECT ID, NAME FROM SOURCE;
目标表字段 多 于源表
多出的字段设置默认值或 NULL
INSERT INTO TARGET(ID, NAME, REMARK) SELECT ID, NAME, '默认值' FROM SOURCE;
目标表有 必填字段 源表没有
必须提供默认值或从其他表关联获取
NVL(SOURCE.REMARK, '无备注')
场景2:字段命名不一致
情况
处理方式
示例
名称不同但含义相同
使用别名映射
SELECT SOURCE.EMP_NAME AS USER_NAME FROM ...
命名规范不同(下划线 vs 驼峰)
显式映射
SELECT SOURCE.employeeId AS EMPLOYEE_ID FROM ...
中文字段名 vs 英文字段名
映射转换
SELECT SOURCE.员工姓名 AS EMP_NAME FROM ...
三、代码示例
示例1:字段数量、命名都不同
sql
复制代码
-- 源表:EMPLOYEES (EMP_ID, EMP_NAME, EMP_SAL, EMP_ADDR, EMP_DEPT)
-- 目标表:TBL_USER (USER_CODE, FULL_NAME, SALARY) -- 只有3个字段,命名不同
INSERT INTO TBL_USER (USER_CODE, FULL_NAME, SALARY)
SELECT
EMP_ID AS USER_CODE, -- 字段映射
EMP_NAME AS FULL_NAME, -- 命名转换
EMP_SAL AS SALARY -- 只取需要的字段,EMP_ADDR和EMP_DEPT丢弃
FROM EMPLOYEES;
示例2:目标表字段更多
sql
复制代码
-- 目标表:TBL_USER (ID, NAME, SALARY, CREATE_TIME, REMARK)
-- 源表只有3个字段,目标表多出 CREATE_TIME 和 REMARK
INSERT INTO TBL_USER (ID, NAME, SALARY, CREATE_TIME, REMARK)
SELECT
EMP_ID,
EMP_NAME,
EMP_SAL,
SYSDATE AS CREATE_TIME, -- 系统默认值
'同步自员工表' AS REMARK -- 固定默认值
FROM EMPLOYEES;
示例3:使用视图统一映射(推荐)
sql
复制代码
-- 创建映射视图,后续同步直接查视图
CREATE OR REPLACE VIEW V_EMP_SYNC AS
SELECT
EMP_ID AS USER_ID,
EMP_NAME AS USER_NAME,
NVL(EMP_SAL, 0) AS SALARY,
DEPT_ID,
'ACTIVE' AS STATUS
FROM EMPLOYEES;
-- 同步时直接使用视图
INSERT INTO TARGET_USER
SELECT * FROM V_EMP_SYNC;
四、字段类型兼容性要求
源类型
兼容的目标类型
注意事项
VARCHAR2
CHAR, VARCHAR2, CLOB
注意长度,过长会截断
NUMBER
NUMBER, VARCHAR2, INTEGER
小数转整数会舍入
DATE
DATE, TIMESTAMP, VARCHAR2
转 VARCHAR2 需 TO_CHAR
CLOB
VARCHAR2(4000), CLOB
超长会报 ORA-22835
TIMESTAMP
DATE, TIMESTAMP
转 DATE 丢失毫秒
sql
复制代码
-- 类型转换示例
INSERT INTO TARGET
SELECT
TO_NUMBER(SOURCE.EMP_ID) AS ID, -- VARCHAR2 → NUMBER
TO_CHAR(SOURCE.SAL_DATE, 'YYYY-MM-DD') AS DATE_STR, -- DATE → VARCHAR2
TO_DATE(SOURCE.CREATE_TIME, 'YYYYMMDD') AS CREATE_DATE, -- 字符串转日期
CAST(SOURCE.AMOUNT AS NUMBER(10,2)) AS AMOUNT -- 显式转换
FROM SOURCE;
五、最佳实践建议
原则
说明
显式映射优于隐式
始终列出字段列表,不要用 SELECT *
使用别名统一命名
让同步脚本清晰易读
字段增减用版本控制
源表结构变更不影响已有同步
ETL工具支持映射
Kettle/DataX/Datastage 可视化字段映射
文档维护映射关系
记录源-目标字段对应表
sql
复制代码
-- ✅ 推荐:显式指定字段
INSERT INTO TARGET (ID, NAME, AMOUNT)
SELECT ID, NAME, AMOUNT FROM SOURCE;
-- ❌ 不推荐:SELECT * (字段增减会导致失败)
INSERT INTO TARGET SELECT * FROM SOURCE;