【问题标题】:insert into... select ... with subquery or without column orderinsert into... select ... 带有子查询或不带列顺序
【发布时间】:2018-07-12 20:14:02
【问题描述】:

我正在使用 Oracle db,我想知道是否可以编写如下内容:

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。我正在考虑将它们重新排序为 INVISIBLE 并返回 VISIBLE,但我的版本不支持它。而且它不会像我需要的那样可重复使用。

【问题讨论】:

    标签: sql oracle


    【解决方案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
    

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

    您还可以更进一步,只包括出现在两个表中的列,或者验证数据类型完全匹配;虽然这需要更多的工作,而且可能没有必要。

    【讨论】:

    • 太好了!谢谢你的回答,第一段代码正是我需要的。
    猜你喜欢
    • 2016-10-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多