在游标声明内的动态 SQL 内的过程内使用字符串
Using string inside a procedure inside a dynamic SQL inside a cursor declaration
我在为光标内的 select 正确指向特定参数时遇到问题。
这是我写的:
create or replace procedure copy_data
is
ds1 varchar2(50) :='string1';
ds2 varchar2(50) :='string2';
seq1 number;
seq2 number;
BEGIN
select NEXT_ID into seq1 from UNIQUE_KEYS where TABLE_NAME='DATA1';
select NEXT_ID into seq2 from UNIQUE_KEYS where TABLE_NAME='DATA2'; -
execute immediate 'CREATE SEQUENCE data1_seq START WITH '||seq1||' INCREMENT BY 1';
execute immediate 'CREATE SEQUENCE data2_seq START WITH '||seq2||' INCREMENT BY 1 CACHE 300';
execute immediate 'CREATE TABLE DA1_IDS (OLD_ID NUMBER(10), NEW_ID NUMBER(10))';
execute immediate
'
Insert into DATA1 (ID,NAME,DESCRIPTION)
select data1_seq.nextval,:ds1,DESCRIPTION
from DATA1 where NAME=:ds2
'
USING ds1, ds2
;
execute immediate
'
DECLARE
v_oldid DATA2.ID%type;
v_newid number;
v_dsfield DATA2%rowtype;
cursor dsc1 is
select dsf.ID, data2_seq.nextval from DATA2 dsf left join DATA1 ds on dsf.DATA1_ID=ds.ID
where ds.NAME='||'string2'||';
cursor dsc2 is
select dsfid.NEW_ID,dsf.FIELD_NAME,dsf.DESCRIPTION,data1_seq.currval
from DATA2 dsf
left join DA1_IDS dsfid on dsf.ID=dsfid.OLD_ID;
begin
open dsc1;
loop
fetch dsc1 into v_oldid,v_newid;
IF dsc1%FOUND THEN
insert into DA1_IDS values (v_oldid,v_newid);
else
exit;
end if;
end loop;
close dsc1;
open dsc2;
loop
fetch dsc2 into v_dsfield;
IF dsc2%FOUND THEN
Insert into DATA2 values v_dsfield;
else
exit;
end if;
end loop;
close dsc2;
END;'
;
END;
现在,错误是 "string2":标识符无效。
我不知道如何告诉我的脚本那里应该有一个字符串值。
或者也许我做得太过火了,也许我应该扭转局面?
我对游标部分使用了动态 SQL,因为它们需要使用序列,并且序列也是通过动态 SQL 创建的,因为它都在一个过程中。
因此,当在游标中使用对序列的引用时,我需要将其隐藏在动态 SQL 中以正确启动它。
但是我不知道如何在光标中的 select 中传递字符串值。
请帮忙
对于您遇到的直接错误,您只需要在 string2
文字值周围使用转义单引号;不知道为什么你现在有串联,但那是不对的。而不是
where ds.NAME='||'string2'||';
使用
where ds.NAME=''string2'';
您也可以使用绑定变量并传入该文字,就像您在第一个动态语句中所做的那样。
我知道自最初的问题以来已经有一段时间了,但回来只是总结一下它是如何完成的。经过多次迭代,多次与语法斗争,脚本看起来像这样:
create or replace procedure copy_data
AUTHID CURRENT_USER
as
ds1 varchar2(50) :='new_label';
ds2 varchar2(50) :='source_label';
dsid varchar2(200);
seq1 number;
seq2 number;
BEGIN
execute immediate 'CREATE TABLE DSID (DSID NUMBER(10))';
dsid := 'insert into DSID (DSID) select ID from DATA1 where NAME= :ds';
execute immediate dsid USING ds2;
select NEXT_ID into seq1 from UNIQUE_KEYS where TABLE_NAME='DATA1';
select NEXT_ID into seq2 from UNIQUE_KEYS where TABLE_NAME='DATA2';
execute immediate 'CREATE SEQUENCE data1_seq START WITH '||seq1||' INCREMENT BY 1';
execute immediate 'CREATE SEQUENCE data2_seq START WITH '||seq2||' INCREMENT BY 1 CACHE 300';
execute immediate 'CREATE TABLE DA1_IDS (OLD_ID NUMBER(10), NEW_ID NUMBER(10))';
execute immediate
'Insert into DATA1 (ID,NAME,DESCRIPTION,...)
select data1_seq.nextval,:ds1,DESCRIPTION,...
from DATA1 where NAME=:ds2' USING ds1, ds2;
execute immediate
'insert into DA1_IDS (OLD_ID, NEW_ID)
select dsf.ID, data2_seq.nextval from DATA2 dsf inner join DSID ds on dsf.DS_ID=ds.DSID';
execute immediate '
DECLARE
v_dsfield DATA2%rowtype;
cursor dsfields2 is
select dsfid.NEW_ID,dsf.FIELD_NAME,dsf.DESCRIPTION,...,data1_seq.currval,...
from DATA2 dsf
inner join DA1_IDS dsfid on dsf.ID=dsfid.OLD_ID
where dsfid.NEW_ID is not NULL;
begin
open dsfields2;
loop
fetch dsfields2 into v_dsfield;
EXIT WHEN dsfields2%NOTFOUND OR dsfields2%NOTFOUND IS NULL;
if dsfields2%ROWCOUNT > 0 THEN
Insert into DATA2 values v_dsfield;
end if;
end loop;
close dsfields2;
END;'
;
实际上它有大约 10 个游标,以类比方式构建,它们都在所有相关表中传播相同键对象的相同 ID,并且可以附加更多相关表,以类比方式动态填充相同的相关表ID
当我开始它的时候,这个主题的总体思路自动在我脑海中出现,如果它是一段漂亮的代码会很好,比如 pl/sql 过程,带有循环(游标),所以我也可以学习或练习一些东西。
在接下来的一个月里,我写了一个脚本来做同样的事情,但是有一个简单的 sql,没有任何游标,循环,甚至没有序列,只是简单的插入到表:)
但是,我写的东西还是用了几次,效果很好,在客户方面也是如此。所以我将 "pretty" 版本粘贴为闭包:)
我在为光标内的 select 正确指向特定参数时遇到问题。
这是我写的:
create or replace procedure copy_data
is
ds1 varchar2(50) :='string1';
ds2 varchar2(50) :='string2';
seq1 number;
seq2 number;
BEGIN
select NEXT_ID into seq1 from UNIQUE_KEYS where TABLE_NAME='DATA1';
select NEXT_ID into seq2 from UNIQUE_KEYS where TABLE_NAME='DATA2'; -
execute immediate 'CREATE SEQUENCE data1_seq START WITH '||seq1||' INCREMENT BY 1';
execute immediate 'CREATE SEQUENCE data2_seq START WITH '||seq2||' INCREMENT BY 1 CACHE 300';
execute immediate 'CREATE TABLE DA1_IDS (OLD_ID NUMBER(10), NEW_ID NUMBER(10))';
execute immediate
'
Insert into DATA1 (ID,NAME,DESCRIPTION)
select data1_seq.nextval,:ds1,DESCRIPTION
from DATA1 where NAME=:ds2
'
USING ds1, ds2
;
execute immediate
'
DECLARE
v_oldid DATA2.ID%type;
v_newid number;
v_dsfield DATA2%rowtype;
cursor dsc1 is
select dsf.ID, data2_seq.nextval from DATA2 dsf left join DATA1 ds on dsf.DATA1_ID=ds.ID
where ds.NAME='||'string2'||';
cursor dsc2 is
select dsfid.NEW_ID,dsf.FIELD_NAME,dsf.DESCRIPTION,data1_seq.currval
from DATA2 dsf
left join DA1_IDS dsfid on dsf.ID=dsfid.OLD_ID;
begin
open dsc1;
loop
fetch dsc1 into v_oldid,v_newid;
IF dsc1%FOUND THEN
insert into DA1_IDS values (v_oldid,v_newid);
else
exit;
end if;
end loop;
close dsc1;
open dsc2;
loop
fetch dsc2 into v_dsfield;
IF dsc2%FOUND THEN
Insert into DATA2 values v_dsfield;
else
exit;
end if;
end loop;
close dsc2;
END;'
;
END;
现在,错误是 "string2":标识符无效。 我不知道如何告诉我的脚本那里应该有一个字符串值。
或者也许我做得太过火了,也许我应该扭转局面?
我对游标部分使用了动态 SQL,因为它们需要使用序列,并且序列也是通过动态 SQL 创建的,因为它都在一个过程中。
因此,当在游标中使用对序列的引用时,我需要将其隐藏在动态 SQL 中以正确启动它。
但是我不知道如何在光标中的 select 中传递字符串值。
请帮忙
对于您遇到的直接错误,您只需要在 string2
文字值周围使用转义单引号;不知道为什么你现在有串联,但那是不对的。而不是
where ds.NAME='||'string2'||';
使用
where ds.NAME=''string2'';
您也可以使用绑定变量并传入该文字,就像您在第一个动态语句中所做的那样。
我知道自最初的问题以来已经有一段时间了,但回来只是总结一下它是如何完成的。经过多次迭代,多次与语法斗争,脚本看起来像这样:
create or replace procedure copy_data
AUTHID CURRENT_USER
as
ds1 varchar2(50) :='new_label';
ds2 varchar2(50) :='source_label';
dsid varchar2(200);
seq1 number;
seq2 number;
BEGIN
execute immediate 'CREATE TABLE DSID (DSID NUMBER(10))';
dsid := 'insert into DSID (DSID) select ID from DATA1 where NAME= :ds';
execute immediate dsid USING ds2;
select NEXT_ID into seq1 from UNIQUE_KEYS where TABLE_NAME='DATA1';
select NEXT_ID into seq2 from UNIQUE_KEYS where TABLE_NAME='DATA2';
execute immediate 'CREATE SEQUENCE data1_seq START WITH '||seq1||' INCREMENT BY 1';
execute immediate 'CREATE SEQUENCE data2_seq START WITH '||seq2||' INCREMENT BY 1 CACHE 300';
execute immediate 'CREATE TABLE DA1_IDS (OLD_ID NUMBER(10), NEW_ID NUMBER(10))';
execute immediate
'Insert into DATA1 (ID,NAME,DESCRIPTION,...)
select data1_seq.nextval,:ds1,DESCRIPTION,...
from DATA1 where NAME=:ds2' USING ds1, ds2;
execute immediate
'insert into DA1_IDS (OLD_ID, NEW_ID)
select dsf.ID, data2_seq.nextval from DATA2 dsf inner join DSID ds on dsf.DS_ID=ds.DSID';
execute immediate '
DECLARE
v_dsfield DATA2%rowtype;
cursor dsfields2 is
select dsfid.NEW_ID,dsf.FIELD_NAME,dsf.DESCRIPTION,...,data1_seq.currval,...
from DATA2 dsf
inner join DA1_IDS dsfid on dsf.ID=dsfid.OLD_ID
where dsfid.NEW_ID is not NULL;
begin
open dsfields2;
loop
fetch dsfields2 into v_dsfield;
EXIT WHEN dsfields2%NOTFOUND OR dsfields2%NOTFOUND IS NULL;
if dsfields2%ROWCOUNT > 0 THEN
Insert into DATA2 values v_dsfield;
end if;
end loop;
close dsfields2;
END;'
;
实际上它有大约 10 个游标,以类比方式构建,它们都在所有相关表中传播相同键对象的相同 ID,并且可以附加更多相关表,以类比方式动态填充相同的相关表ID
当我开始它的时候,这个主题的总体思路自动在我脑海中出现,如果它是一段漂亮的代码会很好,比如 pl/sql 过程,带有循环(游标),所以我也可以学习或练习一些东西。 在接下来的一个月里,我写了一个脚本来做同样的事情,但是有一个简单的 sql,没有任何游标,循环,甚至没有序列,只是简单的插入到表:)
但是,我写的东西还是用了几次,效果很好,在客户方面也是如此。所以我将 "pretty" 版本粘贴为闭包:)