我想确认正确使用以下内容:
1)使用全局变量只从函数中获取一次返回值 (因为我的函数将返回一些序列值)
2)多次在光标内使用该变量
3)所有这些都将在程序中
下面显示了一个示例。
CREATE OR REPLACE Procedure insert_myTable is
--declare variables for insert
v_firstNO VARCHAR2(10);
v_secondNO VARCHAR2(6);
--declare variable to store the sequence number
var_ASeqno varchar2(6);
-- Validation
v_check VARCHAR2 (10 Byte);
v_table_name varchar2(50):='myTable';
cursor c1 is
select distinct firstNO,
secondNO
from (SELECT hdr.someNum firstNO,
-- using variable to assign the sequence no
var_ASeqno secondNO
FROM someOtherTable hdr
WHERE -- some condition
union
SELECT hdr.someNum firstNO,
-- using variable to assign the sequence no
var_ASeqno secondNO
FROM someOtherTable hdr
WHERE -- some other conditions
union
SELECT hdr.someNum firstNO,
-- using variable to assign the sequence no
var_ASeqno secondNO
FROM someOtherTable hdr
WHERE -- some other other conditions
begin
if c1%isopen then
close c1;
end if;
v_check:=null;
FOR i IN c1 LOOP
--assign variables for insert
v_firstNO := i.firstNO ;
v_secondNO := i.secondNO ;
begin
-- calling the Function aSeqNoFunc and assign the
--Sequence Number into the variable var_ASeqno
var_ASeqno := aSeqNoFunc();
select firstNO
into v_check
from myTable a
where firstNO = i.firstNO
and secondNO =i.secondNO;
exception
when no_data_found then
--insert into target table
INSERT INTO myTable (firstNO, secondNO)
values (v_firstNO, v_secondNO);
end ;
end loop;
end;
可以看出,函数' aSeqNoFunc'在插入接近结束之前调用。这些值被分配给变量< var_ApmSeqno'而在光标内部又使用了三次。
谢谢。
答案 0 :(得分:3)
一些建议:
在END;
声明之后,您有一个cursor c1
声明与任何内容都不匹配。您应该从代码中删除它。
进入程序时,无需检查光标是否打开。它不会成功。更好的是,不要使用显式游标声明 - 使用游标FOR-loop。
除非您知道两者之间的区别,否则请使用UNION ALL而不是UNION。 (And go read up on that。99.9%的时间你想要UNION ALL ......)。
但是,由于看起来所有行都是从同一个表中选择的,因此您可以完全取消UNION,如下所示。
在函数开头为变量赋值NULL没有任何好处。如果没有给出其他显式初始化值,变量将初始化为NULL。
IMO对于从序列中返回下一个值的函数没有任何好处。它只是让理解代码更加困难。摆脱FUNCTION aSeqNoFunc
并在适当的时候调用SOME_SEQUENCE.NEXTVAL
- 所以在上面我建议您使用var_ASeqno := SOME_SEQUENCE.NEXTVAL
。
在光标var_ASeqno
打开之前,您需要将值指定给c1
。如上所述,var_ASeqno
在光标打开时将为null,因此光标可能不会返回您期望的内容。但更重要的是,我没有看到任何理由让光标返回var_ASeqno
的值。只需在INSERT语句中使用var_ASeqno
的值或其他任何需要的值。
如果数据尚未存在,请使用MERGE语句插入数据。这避免了尴尬的" SELECT ...捕获NO_DATA_FOUND异常... INSERT在异常处理程序"逻辑。
正如@boneist在她的评论中指出的那样,当我们走到这一步时,光标真的没有意义。您也可以使用MERGE语句在不使用游标的情况下执行INSERT。
所以我尝试将此程序重写为:
CREATE OR REPLACE Procedure insert_myTable is
begin
MERGE INTO MYTABLE m
USING (SELECT FIRSTNO,
SOME_SEQUENCE.NEXTVAL AS SECONDNO
FROM (SELECT DISTINCT hdr.someNum AS FIRSTNO
FROM someOtherTable hdr
WHERE (/* some condition */)
OR (/* some other conditions */)
OR (/* some other other conditions */))) d
ON d.FIRSTNO = m.FIRSTNO AND
d.SECONDNO = m.SECONDNO
WHEN NOT MATCHED THEN INSERT (FIRSTNO, SECONDNO)
VALUES (d.FIRSTNO, d.SECONDNO);
end INSERT_MYTABLE;
分享并享受。
答案 1 :(得分:0)
考虑到您希望插入的所有行都分配了相同的序列号,我想您可能会将您的过程重写为:
create or replace procedure insert_mytable
is
v_seq_no number;
begin
v_seq_no := somesequence.nextval;
merge into mytable tgt
using (select firstno,
v_seq_no secondno
from (select hdr.somenum firstno
from someothertable1 hdr
where -- some condition
union
select hdr.somenum firstno
from someothertable2 hdr
where -- some other conditions
union
select hdr.somenum firstno
from someothertable3 hdr
where -- some other other conditions
)
) src
on (tgt.firstno = src.firstno and tgt.secondno = src.secondno)
when not matched then
insert (tgt.firstno, tgt.secondno)
values (src.firstno, src.secondno);
end insert_mytable;
/
如果这与您尝试做的事情不匹配,请编辑您的问题,以提供有关该程序目标的更多信息。我们将欣赏示例输入和输出数据,以便我们更好地了解您的需求(因为我们无法查看您的表结构,数据等)。
ETA:有关基于集合和逐行方法之间性能考虑的信息。
这是一个简单的脚本,可以插入一百万行,包括逐行和单个插入语句:
create table test (col1 number,
col2 number);
set timing on;
-- row-by-row (aka slow-by-slow) approach
begin
for rec in (select level col1, level * 10 col2
from dual
connect by level <= 1000000)
loop
insert into test (col1, col2)
values (rec.col1, rec.col2);
end loop;
end;
/
commit;
truncate table test;
-- set based approach (keeping in an anonymous block for comparison purposes)
begin
insert into test (col1, col2)
select level, level*10
from dual
connect by level <= 1000000;
end;
/
commit;
drop table test;
这是我得到的输出,当我在Toad中运行上述内容时:
Table created.
PL/SQL procedure successfully completed.
Elapsed: 00:00:21.87
Commit complete.
Elapsed: 00:00:01.03
Table truncated.
Elapsed: 00:00:00.22
PL/SQL procedure successfully completed.
Elapsed: 00:00:01.96
Commit complete.
Elapsed: 00:00:00.03
Table dropped.
Elapsed: 00:00:00.18
您是否看到逐行方法的经过时间为21秒,基于集合的方法为2秒?性能差异很大,你不同意吗?如果没有理由考虑将您的代码编写为基于第一个实例的设置,那么我不知道还有什么能说服您/您的老板!