我有一个包含两行的表,我需要将行A中的一些数据复制到行B. 我最关心的是所涉及的列在名称或编号上不是静态的(表格可以在列号中增长或缩小)。
我想出了一个我根本不喜欢的解决方案......
create or replace
PROCEDURE Z_COPY_TASK_ATT_PE
(
par_oldRowId IN VARCHAR2,
par_newRowId IN VARCHAR2
)
IS
var_update VARCHAR2(4000 BYTE);
var_crr_col_value_old VARCHAR2(10 BYTE);
var_crr_select VARCHAR2(4000 BYTE);
BEGIN
var_update := 'UPDATE PLANNING_ENTITY SET ';
for i in (
Select COLUMN_NAME
from user_tab_columns
where table_name='PLANNING_ENTITY'
and lower(COLUMN_NAME) like 'code%'
)
loop
var_crr_select := 'select ' || i.column_name
|| ' from planning_entity where planning_code = '''
|| par_oldRowId || '''';
execute immediate var_crr_select
into var_crr_col_value_old;
var_update := var_update || i.column_name || ' = ''' || var_crr_col_value_old || ''', ';
end loop;
var_update := SUBSTR(var_update, 0, length(var_update)-2 );
var_update := var_update || ' where planning_code = ''' || par_newRowId || '''';
execute immediate var_update;
commit;
END;
我的主要问题(至少对我而言)是我需要为循环的每次迭代进行选择。如果我可以选择返回类似列名的选项,那将是非常好的,然后我需要做的就是i.column和i.value。
您怎么看?
=====关于Marmite Bomber的解决方案答案=====
create or replace
PROCEDURE Z_COPY_TASK_ATT_PE
(
par_oldRowId IN VARCHAR2,
par_newRowId IN VARCHAR2
)
IS
var_update VARCHAR2(4000 BYTE);
var_columns varchar2(4000 BYTE);
BEGIN
Select LISTAGG(COLUMN_NAME, ',') WITHIN group (order by column_name) into var_columns
from user_tab_columns
where table_name='PLANNING_ENTITY'
and lower(COLUMN_NAME) like 'code%';
var_update := 'UPDATE PLANNING_ENTITY PE1 SET (' || var_columns ||
') = (SELECT ' || var_columns || ' FROM PLANNING_ENTITY PE2 WHERE PE2.PLANNING_CODE = ''' || par_oldRowId ||
''') WHERE PE1.PLANNING_CODE = ''' || par_newRowId || '''';
execute immediate var_update;
commit;
END;
答案 0 :(得分:3)
基于此更新
UPDATE t1 a
SET (code1, code2) = (
SELECT code1,code2
FROM t1 b
WHERE b.planning_code = 'new')
where a.planning_code = 'old';
您只需生成应更新的列名的逗号分隔列表,并在语句中应用两次。在示例 code1,code2 。
中答案 1 :(得分:0)
这个怎么样?
begin
for i in (select * from PLANNING_ENTITY where planning_code = newrow) loop
update PLANNING_ENTITY set row = i where planning_code = oldrow;
end loop;
end;
对于downvoters:
SQL> select version from v$instance;
VERSION
-----------------
11.2.0.4.0
SQL> create table it_works_in_oracle (n1 number, n2 number, n3 number);
Table created.
SQL> insert into it_works_in_oracle values(1, 1, 1);
1 row created.
SQL> insert into it_works_in_oracle values(2, 2, 2);
1 row created.
SQL> insert into it_works_in_oracle values(3, 3, 3);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from it_works_in_oracle;
N1 N2 N3
---------- ---------- ----------
1 1 1
2 2 2
3 3 3
SQL> set serveroutput on
SQL> declare
oldrow number:=1;
newrow number:=3;
begin
for i in (select * from it_works_in_oracle where n1 = newrow) loop
update it_works_in_oracle set row = i where n1 = oldrow;
end loop;
end; 2 3 4 5 6 7 8
9 /
PL/SQL procedure successfully completed.
SQL> select * from it_works_in_oracle;
N1 N2 N3
---------- ---------- ----------
3 3 3
2 2 2
3 3 3
答案 2 :(得分:0)
您可以这样做(未经测试):
var_update := 'UPDATE PLANNING_ENTITY a SET (';
FOR i IN (
SELECT COLUMN_NAME
FROM USER_TAB_COLUMNS
WHERE table_name='PLANNING_ENTITY'
AND LOWER(COLUMN_NAME) LIKE 'code%'
)
LOOP
var_update := var_update || i.column_name ||',';
END LOOP;
var_update := REGEXP_REPLACE(var_update, ',$', ')');
var_update := var_update ||' = (SELECT ';
FOR i IN (
SELECT COLUMN_NAME
FROM USER_TAB_COLUMNS
WHERE table_name='PLANNING_ENTITY'
AND LOWER(COLUMN_NAME) LIKE 'code%'
)
LOOP
var_update := var_update || i.column_name ||',';
END LOOP;
var_update := REGEXP_REPLACE(var_update, ',$');
var_update := var_update || ' FROM PLANNING_ENTITY b WHERE planning_code = :newRowId) ';
var_update := var_update || ' WHERE a.planning_code = :oldRowId';
EXECUTE IMMEDIATE var_update USING par_newRowId, par_oldRowId;