如何复制一组行只更改一列的值而不列出其他列?

时间:2011-09-21 13:44:01

标签: database oracle

给定一个表T(x, y, z, t, u, v, ...)是否可以在Oracle中编写此查询而不列出所有列(在SELECT或INSERT部分中)?

INSERT INTO T (x, y, z, t, u, v, ...)
SELECT 'new', y, z, t, u, v, ...
  FROM T
 WHERE x = 'old'

效果是x具有 old 值的所有行都是重复的,但现在x的值为 new

3 个答案:

答案 0 :(得分:2)

  

“在Oracle中可以编写此查询而不列出所有内容   列(在SELECT或INSERT部分中)“

没有。避免键入显式投影的唯一方法是使用所有表的列。您没有这样做,因为您想使用文字而不是列X。这意味着您必须列出SELECT投影中的所有其他列。

当然,您不必在INSERT子句中指定列。

多年来,开发人员偶尔希望使用“except”语法,例如:

select * except X from t

但它从未进入ANSI标准。事实上,我怀疑它是否被讨论过。


  

“欢迎PLSQL回答!”

好的,这是一个概念证明,它使用数据字典生成动态插入语句。

它做出以下假设:

  1. 您只想替换一列的值。
  2. 要替换的列是字符串数据类型。
  3. 您想要克隆源表中的所有记录。
  4. 如果任何这些假设错误,您将需要调整代码。

    该过程遍历USER_TAB_COLUMNS表,将列排序为表的预计顺序。它将列名连接到INSERT语句的SELECT子句中,除非在连接提供的文字时,名称是替换列的名称。最后,它使用Native Dynamic SQL来运行汇编的INSERT语句。

    create or replace procedure clone_minus_one 
        ( p_sub_col in user_tab_columns.column_name%type
          , p_sub_val in varchar2 )
    is
        stmt varchar2(32767) := 'insert into source_table select ';
    begin
        for lrec in ( select column_name
                             , column_position 
                      from  user_tab_columns.
                      where table_name = 'SOURCE_TABLE'
                      order by column_position )
        loop
            if lrec.column_position != 1
            then 
                stmt := stmt ||',';
            end if;
            if lrec.column_name != p_sub_col
            then
                stmt := stmt ||lrec.column_name;
            else
                stmt := stmt ||''''||p_sub_val||'''';
            end if;  
        end loop;
        stmt := stmt || ' from source_table';
        execute immediate stmt;
    end;
    /
    

答案 1 :(得分:1)

如果所选列正确排序,您可以完全按照您的描述进行操作。

以下是有效

INSERT INTO T 
SELECT 'new', y, z, t, u, v, ...
  FROM T
 WHERE x = 'old'

或者你可以尝试这个(粗略的脚本未经测试)

CREATE TABLE TEMPTABLE AS SELECT * FROM T WHERE X = 'Old';

UPDATE TEMPTABLE SET X='New';

INSERT INTO T (SELECT * FROM TEMPTABLE);

DROP TABLE TEMPTABLE;

答案 2 :(得分:0)

以下是太过分了,以避免一些打字imo,但我喜欢挑战,所以在这里... ...

insert into T
select * from T
where x='old';
commit;

-- update every other row to 'new'
update T
set x='new'
where rowid in
(
select rowid from
  (select rownum rnum, rowid row_id
   from T
   where x='old'
  )
where mod(rnum,2)=0
);
commit;

分2步,但我个人只是查询表的all_tab_columns(按column_id排序)并复制/粘贴到我的脚本/过程中。但可能是其他一些避免这种情况的原因,不确定。