一尘不染

插入带有子查询或不带列顺序的“ select”中

sql

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


阅读 204

收藏
2021-03-17

共1个答案

一尘不染

不,您不能使用子查询来生成列列表作为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

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

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

2021-03-17