Oracle Ref游标与选择到(带异常处理)

vfhzx4xs  于 2023-05-22  发布在  Oracle
关注(0)|答案(6)|浏览(164)

我有几个场景:
1.需要以预定义的顺序从三个不同的表中读取列的值,并且只有一个表具有数据
1.如果存在给定条件的记录,则从表1读取数据,否则从表2读取给定条件的数据
Oracle存储过程
现在处理这些的方法是首先将给定查询的计数值获取到变量中,如果计数> 0,则执行相同的查询来读取实际数据,如:

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

这样做是为了避免no_data_found异常,否则我将需要三个异常处理程序块来捕获每个表访问的no_data_found异常。
目前我正在用Cursors重新实现它,这样我就有了这样的东西:

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

我想从性能的Angular 找出哪一个更好--带Cursors的,还是对变量进行Select并有三个no_data_found Exception块的。我不想使用我们目前使用的两阶段查询过程。

ljo96ir5

ljo96ir51#

我不知道你为什么如此热衷于避免例外?什么是错误的:

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

我相信这会比你的其他解决方案表现得更好,因为它做了最少的工作来达到预期的结果。
请参阅How bad is ignoring Oracle DUP_VAL_ON_INDEX exception?,其中我演示了使用异常比计数来查看是否有任何数据的性能更好。

9lowa7mx

9lowa7mx2#

select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

不等同于

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

在多用户环境中。在第一种情况下,某人可以在您检查存在性和读取数据之间更新表。
就性能而言,我不知道哪个更好,但我知道第一个选项对sql引擎进行了两次上下文切换,而第二个选项只进行了一次上下文切换。

bpsygsoo

bpsygsoo3#

你现在处理第一种情况的方式不好。当一个查询就足够了的时候,你不仅要做两个查询,而且正如Erik指出的那样,它打开了两个查询之间数据更改的可能性(除非你使用只读或可序列化的事务)。
假设您说在这种情况下数据将正好位于三个表中的一个,那么下面这个怎么样?

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

另一个可以用来避免编写多个未找到数据的处理程序的“技巧”是:

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

但我真的看不出有什么理由比有三个异常处理程序更好。
对于第二种情况,我认为您的意思是两个表中可能都有数据,如果存在,您希望使用表1中的数据,否则使用表2中的数据。同样,您可以在单个查询中执行此操作:

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1
at0kjp5o

at0kjp5o4#

“Dave Costa”的MIN选项的增强版本...

SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

现在可以检查v_rowcount的值0,>1(大于1),其中正常的选择查询将抛出NO_DATA_FOUNDTOO_MANY_ROWS异常。值“1”将指示恰好存在一行,并将用于我们的目的。

b09cbbtk

b09cbbtk5#

DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/
41zrol4v

41zrol4v6#

使用“for row in cursor”形式的循环,如果没有数据,循环将不会处理:

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;

相关问题