使用SSMA迁移Oracle至SQL Server后,无法创建复合主键主外键关系
刚处理过好几起SSMA两步法迁移后外键创建失败的案例,结合你提到的BILL_INFO和BILL_INFO_DETAIL复合主键主从关系场景,给你梳理几个最可能的根因和解决步骤:
1. 先排查复合键字段的类型/属性是否完全匹配
Oracle和SQL Server的数据类型映射经常会有“隐形差异”,SSMA自动转换后可能出现字段类型、长度、精度不统一的情况——这是外键创建失败的头号原因。
比如主表BILL_INFO的复合主键是(BILL_ID NUMBER(12), BILL_TYPE VARCHAR2(10)),但SSMA可能把从表BILL_INFO_DETAIL对应的字段转成了(BILL_ID INT, BILL_TYPE VARCHAR(15)),哪怕长度差一点,外键约束都无法建立。
操作步骤:
执行以下SQL对比两张表的字段定义:
-- 查询主表复合主键字段的详细属性 SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'BILL_INFO' AND COLUMN_NAME IN ('你的主键字段1', '你的主键字段2'); -- 查询从表对应外键字段的详细属性 SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'BILL_INFO_DETAIL' AND COLUMN_NAME IN ('对应的外键字段1', '对应的外键字段2');
确保每一组对应字段的类型、长度、精度、是否允许NULL完全一致(主键字段都是NOT NULL,外键字段也必须是NOT NULL)。
2. 检查从表是否存在违反外键约束的脏数据
迁移过程中,Oracle里的脏数据(比如从表存在主表没有的主键值、或者外键字段为NULL)会被带到SQL Server,导致外键约束创建失败。
操作步骤:
执行以下SQL找出违规数据:
SELECT d.* FROM BILL_INFO_DETAIL d LEFT JOIN BILL_INFO m ON d.外键字段1 = m.主键字段1 AND d.外键字段2 = m.主键字段2 WHERE m.主键字段1 IS NULL OR m.主键字段2 IS NULL;
对于这些数据,你可以选择:
- 删除不符合约束的记录
- 将外键字段修正为主表中存在的主键值
- 如果业务允许,先创建允许NULL的外键(不推荐,除非有特殊需求)
3. 确认主表复合主键是否真的生效,且字段顺序一致
有时候SSMA迁移后主表的复合主键可能没有正确创建,或者你创建外键时的字段顺序和主键的顺序不匹配——外键的字段顺序必须和主键的定义顺序完全对应。
操作步骤:
先确认主表的复合主键结构:
SELECT CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'BILL_INFO' AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY ORDINAL_POSITION;
确保你创建外键时指定的字段顺序,和这里的ORDINAL_POSITION顺序完全一致。
4. 排查权限或锁表问题
如果以上都没问题,可能是当前用户没有ALTER TABLE权限,或者从表被其他进程锁住了。
操作步骤:
- 检查当前用户权限:
返回1表示有权限,返回0则需要给用户赋予ALTER权限。SELECT HAS_PERMS_BY_NAME('BILL_INFO_DETAIL', 'OBJECT', 'ALTER'); - 检查锁表情况:
执行sp_who2查看是否有进程占用BILL_INFO_DETAIL表,杀掉对应的锁进程后再尝试创建外键。
内容的提问来源于stack exchange,提问作者DoomerDGR8

