ORA-14097 是因交换表与原表在 sys.col$ 中字节级不一致(如 column_id、data_length、nullable、默认值、隐藏列等任一差异)导致,CTAS 会丢失所有结构元数据,必须用 DBMS_METADATA.GET_DDL 重建表而非 ALTER 修复。

ORA-14097 不是“数据类型写错了”——它根本不是在比对语义,而是 Oracle 在 sys.col$ 字典里逐字段做字节级校验,只要 column_id、data_type、data_length、nullable、默认值、隐藏列或未使用列中任一不一致,就立刻报错,且不告诉你哪一列出了问题。
为什么 CTAS 建的交换表必报 ORA-14097
用 CREATE TABLE AS SELECT * 建交换表,表面省事,实则丢掉所有结构元数据:
-
column_id物理顺序错位(比如源表是id, name, created_at,CTAS 写成SELECT name, id, created_at,column_id就完全对不上) - 所有
NOT NULL约束丢失(nullable = 'Y'而非'N') - 默认值(
DEFAULT SYSDATE变成DEFAULT NULL)被清空,default$字段在sys.col$中值不同 - 隐藏列(
hidden_column = 'YES')、虚拟列、未使用列(unused_col)全部消失
Oracle 交换时根本不看 DDL 文本是否“看起来一样”,只读 sys.col$ 的原始记录。哪怕只差一个字节(如 VARCHAR2(50) 和 VARCHAR2(50 CHAR)),就触发错误。
怎么定位到底是哪一列不一致
别靠 DESC 或肉眼比 DDL。必须查字典视图,逐项比对:
- 列顺序和
column_id:SELECT column_name, column_id FROM user_tab_columns WHERE table_name IN ('PART_TABLE', 'STAGING_TABLE') ORDER BY table_name, column_id - 类型细节:
SELECT column_name, data_type, data_length, data_precision, nullable FROM user_tab_columns WHERE table_name IN ('PART_TABLE', 'STAGING_TABLE') ORDER BY table_name, column_id - 隐藏列与虚拟列:
SELECT column_name, hidden_column, virtual_column FROM user_tab_cols WHERE table_name IN ('PART_TABLE', 'STAGING_TABLE') AND (hidden_column = 'YES' OR virtual_column = 'YES') - 未使用列:
SELECT column_name FROM user_tab_cols WHERE table_name = 'STAGING_TABLE' AND unused_col_count > 0
注意:data_length 必须完全相等——TIMESTAMP(6) 在不同上下文下可能存为 11 或 20;VARCHAR2(100) 和 VARCHAR2(100 CHAR) 的 data_length 值不同,直接不通过。
修复必须重建,不能 ALTER 补救
ALTER TABLE MODIFY 或 ADD CONSTRAINT 只能补部分表象(比如加个 NOT NULL),但无法修正底层字节级差异:
-
column_id错位无法通过ALTER调整 - 隐藏列、未使用列、
default$内部表达式无法用ALTER还原 - 主键约束状态(
ENABLED VALIDATED)必须严格对齐,NOT VALIDATED也会失败
正确做法是:DBMS_METADATA.GET_DDL('TABLE', 'PART_TABLE') 拿到原始 DDL,手工替换表名、去掉分区子句、补全约束后执行建表。手写时注意保留换行与逗号位置——Oracle 对 DDL 文本格式敏感,尤其涉及默认值和注释时。
最易被忽略的是:即使所有列名、类型、长度都对得上,只要有一列的 default$ 字段在 sys.col$ 中字节不同(比如 SYSDATE vs CURRENT_DATE),或者某列在源表是隐藏列而交换表不是,就会静默失败。查 sys.col$ 需要 DBA 权限,日常应优先依赖 user_tab_columns + user_tab_cols 组合校验,把比对过程脚本化,避免每次靠人眼扫。


















