我正在使用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。我当时正在考虑重新排序,以将它们引导至“不可见”并返回“可见”,但我的版本不支持此功能。而且它不会像我需要的那样可重用。
答案 0 :(得分:2)
否,您不能使用子查询来生成列列表作为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
如果您可能想经常这样做,那么您也可以将该匿名块转换为采用两个表名的过程(您说它需要可重用,但这可能意味着相同的表,并且可能只是脚本中的一个块)。
您还可以走得更远,只包括出现在两个表中的列,或者验证数据类型是否完全匹配;尽管还有更多工作,可能完全没有必要。