tags:

views:

89

answers:

7

During my job, I usually have to copy rows while changing their primary key and giving them a new stamp and maybe changing the foreign key.

The problem is I don't want to type all the column names while doing;

insert into table_name
select pk_seq.nextval, 
       'foreign-key', 
       col3,
       col4...col51
  from table_name
 where pk_id = "original_primary_key"

And if i do * in the select statement i won't be able to update the first 2 columns...

Is there any way to do how I want to do it?

+2  A: 

Sorry - it's an all or nothing affair.
There isn't anything between SELECT * and list the specific columns, it's one or the other.

OMG Ponies
A: 

How about creating a stored procedure that takes the original primary key in parameter, builds the insert query dynamically and executes it

vc 74
+10  A: 

Well it may not be much less verbose, but this PL/SQL is an option:

begin
  for r in (select *
              from table_name
             where pk_id = 'original_primary_key')
  loop
    r.pk := pk_seq.nextval;
    r.fk := 'foreign-key';
    insert into table_name values r;
  end loop;
end;
Tony Andrews
+1: Implicit cursor, nice!
OMG Ponies
Is there another kind? ;-)
Tony Andrews
+1 Nice. Note for people who are not on Oracle 11g, the line `r.pk := pk_seq.nextval;` should be replaced by `select pk_seq.nextval into r.pk from dual;`
Shannon Severance
A BULK COLLECT / BULK INSERT cursor might work even better. PL/SQL in 10g+ implicitly bulks the implicit cursor, but you're still doing a PL/SQL -> SQL -> PL/SQL context switch on every insert.
Adam Musch
@Adam Musch: The cursor should process at most one row, since the `where` clause has an equality test on the primary key. With only one row, bulk collect/bulk insert would not buy anything.
Shannon Severance
I completely didn't notice the "and pk = 'primary key value'"; I had the arbitrary/general case in my head.
Adam Musch
A: 

You could make a simple stored procedure that take a table name and using the data dictionary writes the select statement text for you (the text of the select). Then copy, paste and Modify.

Jonathan
+2  A: 

Based on Tony's answer:

We know that at most one row will be returned since we are searching on primary key. And assuming that a valid key value is specified, at least one row will be returned. So we don't need the loop:

declare
    r table_name%ROWTYPE;
begin
    select *
    into r
    from table_name
    where pk_id = "original_primary_key";
-- 
    select pk_seq.nextval into r.pk_id from dual;
     -- For 11g can use instead: r.pk_id := pk_seq.nextval;
    r.fk_id := "new_foreign_key";
    insert into table_name values r;
end;
Shannon Severance
+2  A: 

You could just query the data dictionary to generate the SQL for you.

SELECT 'tbl.' || column_name || ','
FROM   user_tab_columns
WHERE  table_name = 'MYTABLE'
ORDER BY column_id;

Get the result of this query, paste into your SQL statement, adapt as necessary, and voila.

Jeffrey Kemp
A: 

You can create a 'temp' table, update two columns and do an insert-select from this 'temp' table.

Eaxmple:

create table temptemp as 
select *
  from table_name
 where pk_id = "original_primary_key"

update temptemp
set col1 = ...
,   col2 =....

insert into table2
select * from temptemp;
TTT