插入...选择...有子查询或无列顺序

时间:2018-07-12 09:14:39

标签: sql oracle

我正在使用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。我当时正在考虑重新排序,以将它们引导至“不可见”并返回“可见”,但我的版本不支持此功能。而且它不会像我需要的那样可重用。

1 个答案:

答案 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

如果您可能想经常这样做,那么您也可以将该匿名块转换为采用两个表名的过程(您说它需要可重用,但这可能意味着相同的表,并且可能只是脚本中的一个块)。

您还可以走得更远,只包括出现在两个表中的列,或者验证数据类型是否完全匹配;尽管还有更多工作,可能完全没有必要。