我正在使用Oracle数据库,我想知道是否可以编写类似以下内容的代码:
INSERT INTO CL (select COLUMN_NAME from USER_TAB_COLUMNS where TABLE_NAME='CL') SELECT * FROM CLT;
或者:
INSERT INTO CL (select COLUMN_NAME from USER_TAB_COLUMNS where TABLE_NAME='CL') SELECT (select COLUMN_NAME from USER_TAB_COLUMNS where TABLE_NAME='CL') FROM CLT;
因此,想法是两个表都具有相同的列,但列顺序不匹配,所以当我尝试做简单时
INSERT INTO CL SELECT * FROM CLT;
我一直在收到ORA-00932:不一致的数据类型,如果我一一指定所有列就不会发生。但是我不想这样做,因为我的表有约50列,而且我想拥有一个健壮的解决方案,以后也可以将其应用于其他表。
这就是为什么我在考虑使用子查询在INSERT INTO查询中获取列名的原因,但是这在sql中是不可能的,或者我做错了什么。
是否有任何方法可以跳过其中的列顺序(并强制sql使用名称?)或在该查询中使用子查询以相同顺序获得两倍的所有列名称?
PS。我当时正在考虑重新排序,以将它们引导至“不可见”并返回“可见”,但我的版本不支持此功能。而且它不会像我所需要的那样可重用。
不,您不能使用子查询来生成列列表作为SQL语句的一部分。
您可以从数据字典生成完整的语句:
select 'insert into cl ("' || listagg(column_name, '","') within group (order by column_id) || '") select "' || listagg(column_name, '","') within group (order by column_id) || '" from clt' from user_tab_columns where table_name = 'CLT';
然后复制并粘贴,或者使用匿名块中的动态SQL:
declare stmt varchar2(4000); begin select 'insert into cl ("' || listagg(column_name, '","') within group (order by column_id) || '") select "' || listagg(column_name, '","') within group (order by column_id) || '" from clt' into stmt from user_tab_columns where table_name = 'CLT'; dbms_output.put_line(stmt); -- to check and debug execute immediate stmt; end; /
有几个虚拟表:
create table clt (col1 number, col2 date, col3 varchar2(10)); create table cl (col3 varchar2(10), col1 number, col2 date); insert into clt (col1, col2, col3) values (42, date '2018-07-12', 'Test'); insert into cl select * from clt; SQL Error: ORA-00932: inconsistent datatypes: expected NUMBER got DATE
运行该块可以得到:
insert into cl ("COL1","COL2","COL3") select "COL1","COL2","COL3" from clt PL/SQL procedure successfully completed. select * from cl; COL3 COL1 COL2 ---------- ---------- ---------- Test 42 2018-07-12
如果您经常想做的话,您也可以将该匿名块转换为采用两个表名的过程(您说它需要可重用,但这可能意味着相同的表,并且可能只是脚本中的一个块)。
您还可以走得更远,只包括出现在两个表中的列,或者验证数据类型是否完全匹配;尽管还有更多工作,可能完全没有必要。