当心 CREATE TABLE AS

本文探讨了在Oracle数据库中使用CREATETABLEAS指令时可能遇到的问题,包括非空约束、默认约束、唯一约束丢失的情况,并提供了解决方案。
对 DBA 而言,CREATE TABLE AS 可谓是家常便饭,顺手拈来。需不知该方式虽然简单,但疏忽也容易导致意想不到的问题。笔者前阵子就碰上
了这样的事情。由于是对原表进行克隆,且数据存储在不同的表空间,因此毫不犹豫地使用了CREATE TABLE AS,结果在运行package时,error...

--1、非空约束遗失 -->使用create table as 来创建对象 scott@CNMMBO> create table tb_dept as select * from dept where 1=0; Table created. scott@CNMMBO> desc dept; Name Null? Type ----------------------------------------------------- -------- ------------------------------------ DEPTNO NOT NULL NUMBER(2) DNAME VARCHAR2(14) LOC VARCHAR2(13) scott@CNMMBO> desc tb_dept; Name Null? Type ----------------------------------------------------- -------- ------------------------------------ DEPTNO NUMBER(2) DNAME VARCHAR2(14) LOC VARCHAR2(13) -->从上面的desc可以看出新创建的表少了非空约束 -->下面手动为其增加非空约束,增加后与原来的表是一致的。当然使用create table as时,索引是需要单独重建的。 scott@CNMMBO> alter table tb_dept modify (deptno not null); Table altered. scott@CNMMBO> drop table tb_dept; -->删除刚刚穿件的表tb_dept Table dropped. --2、存在非空约束时default约束遗失 -->下面为表dept的loc列添加非空约束,且赋予default值 scott@CNMMBO> alter table dept modify (loc default 'BeiJing' not null); Table altered. -->为原始表新增一条记录 scott@CNMMBO> insert into dept(deptno,dname) select 50,'DEV' from dual; 1 row created. scott@CNMMBO> commit; Commit complete. -->下面的查询可以看到新增记录50的loc为缺省值'BeiJing' scott@CNMMBO> select * from dept; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 50 DEV BeiJing -->再次使用create table as来创建对象 scott@CNMMBO> create table tb_dept as select * from dept; Table created. -->从下面可知,由于列loc存在default值,所以此时not null约束被同时赋予 scott@CNMMBO> desc tb_dept Name Null? Type ----------------------------------------------------- -------- ------------------------------------ DEPTNO NUMBER(2) DNAME VARCHAR2(14) LOC NOT NULL VARCHAR2(13) scott@CNMMBO> select * from tb_dept; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 50 DEV BeiJing -->为新创建的表新增记录 -->新增时发现尽管not null约束生效,但原表上设定的default值不存在了 scott@CNMMBO> insert into tb_dept(deptno,dname) select 60,'HR' from dual; insert into tb_dept(deptno,dname) select 60,'HR' from dual * ERROR at line 1: ORA-01400: cannot insert NULL into ("SCOTT"."TB_DEPT"."LOC") scott@CNMMBO> drop table tb_dept; Table dropped. --3、唯一约束遗失 scott@CNMMBO> alter table dept modify (dname unique); Table altered. scott@CNMMBO> create table tb_dept as select * from dept; Table created. scott@CNMMBO> insert into tb_dept select 60,'DEV','ShangHai' from dual; 1 row created. scott@CNMMBO> commit; Commit complete. scott@CNMMBO> select * from tb_dept; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 50 DEV BeiJing 60 DEV ShangHai -->有关check约束与外键约束不再演示 --4、最彻底的解决办法 scott@CNMMBO> select dbms_metadata.get_ddl('TABLE','DEPT') from dual; DBMS_METADATA.GET_DDL('TABLE','DEPT') -------------------------------------------------------------------------------- CREATE TABLE "SCOTT"."DEPT" ( "DEPTNO" NUMBER(2,0), "DNAME" VARCHAR2(14), "LOC" VARCHAR2(13) DEFAULT 'BeiJing' NOT NULL ENABLE, CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "GOEX_USERS_TBL" ENABLE, UNIQUE ("DNAME") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "GOEX_USERS_TBL" ENABLE ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "GOEX_USERS_TBL" --5、演示环境 scott@CNMMBO> select * from v$version where rownum<2; BANNER ---------------------------------------------------------------- Oracle Database 10g Release 10.2.0.3.0 - 64bit Production --6、演示结论 -->create table as 尽管会克隆表及数据,数据是完整的,但是结构部分仅仅是部分克隆 -->create table as 会使用表上的约束被遗失或出于非正常状态 -->create table as 时,表上的索引、触发器等不会被同时克隆 -->create table as 仅作测试使用,要得到完整的结构语句,还是使用dbms_metadata.get_ddl包 -->Author: Robinson Cheng -->Blog: http://blog.youkuaiyun.com/robinson_0612

更多参考:

启用用户进程跟踪

父游标、子游标及共享游标

绑定变量及其优缺点

dbms_xplan之display_cursor函数的使用

dbms_xplan之display函数的使用

执行计划中各字段各模块描述

使用 EXPLAIN PLAN 获取SQL语句执行计划

启用 AUTOTRACE 功能

函数使得索引列失效

Oracle 绑定变量窥探





select b.serial, b.msgtype, b.TERNO, b.LOCAL_DATE, b.LOCAL_TIME, b.bid, b.pan, b.pan_enc, '****' as PAN_BMASK, b.amount * 0.01 as amount, b.ADD_CHARGE_TYPE, case when b.status = '9' then b.DISPOSE_RC else b.rc end as rc, b.status, b.stan, b.rrno, b.air, b.dd, b.cati, mi.MERNO, substr(b.inputtype, 0, 2) as inputtype, b.cardtype, b.sett_type, b.AU_STATE, b.MER_NO, mi.MER_NAME, ats.screen_name, mi.mer_type, b.MER_RATE_TYPE, b.pay_type, b.TRADE_CHARGES * 0.01 as TRADE_CHARGES, b.RECEIVABLE_ACT_ADD_CHARGE * 0.01 as RECEIVABLE_ACT_ADD_CHARGE, ri.ARMARK_FL as MER_RATE, a.AGENT_NUM, a.SHOW_AGENT_NUM, a2.AGENT_NAME as SHOW_AGENT_NAME from ( with recursive agent_down_tree as ( select agent_num, agent_name, agent_level, belong_agent from web_db.agent_info where agent_num = 100055691 union all select agall.agent_num, agall.agent_name, agall.agent_level, agall.belong_agent from web_db.agent_info agall join agent_down_tree aha on agall.belong_agent = aha.agent_num ) select ai.agent_num, ai.agent_name, case when ai.agent_num = 100055691 then ai.agent_num else ( with recursive agent_up_line as ( select agent_num, agent_level, belong_agent from web_db.agent_info where agent_num = ai.agent_num union all select aii.agent_num, aii.agent_level, aii.belong_agent from web_db.agent_info aii join agent_up_line aul on aul.belong_agent = aii.agent_num ) select agent_num from agent_up_line where agent_level = ( select AGENT_LEVEL + 1 from agent_info where agent_num = 100055691) ) end as show_agent_num from agent_down_tree ai ) a inner join WEB_DB.AGENT_INFO a2 on a2.AGENT_NUM = a.SHOW_AGENT_NUM inner join WEB_DB.MERCHANT_INFO mi on mi.AGENT_NO = a.AGENT_NUM inner join WEB_DB.bank_expenditure b on b.MER_NO = mi.MERNO left join WEB_DB.accounts ats on mi.MERNO = ats.seq_id left join WEB_DB.RATE_INFO ri on ri.AR_MARK = b.AR_MARK where b.status <> 3 and b.LOCAL_DATE >='2025-07-01' and b.LOCAL_DATE <= '2025-07-07' order by b.serial desc limit 0,30000 ; 优化上面的sql
最新发布
08-14
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值