我有几个场景:
需要以预定义的顺序从三个不同的表中读取列的值,并且只有一个表具有数据
如果对于给定的标准存在记录,则从table1读取数据否则从表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异常。
目前我正在用游标重新实现这一点,以便我有这样的东西:
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
我想从性能的角度找出哪一个更好 - 一个是Cursors,另一个是选择变量并且有三个no_data_found异常块。我不想使用我们目前的两阶段查询过程。
答案 0 :(得分:5)
我不知道为什么你如此热衷于避免异常?有什么问题:
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?,其中我证明使用异常的效果优于计数以查看是否有任何数据。
答案 1 :(得分:4)
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引擎,第二个选项只进行一个上下文切换。
答案 2 :(得分:1)
现在处理方案1的方式并不好。当一个人满足要求时,你不仅要做两个查询,而且正如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...
但我没有看到任何理由比拥有三个异常处理程序更好。
对于你的第二个场景,我认为你的意思是两个表中都可能有数据,你想使用table1中的数据(如果存在),否则使用表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
答案 3 :(得分:1)
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;
/
答案 4 :(得分:1)
“Dave Costa”的MIN选项的增强版......
SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;
现在v_rowcount
可以检查值0,> 1(大于1),其中普通选择查询将抛出NO_DATA_FOUND
或TOO_MANY_ROWS
异常。值“1”表示确实存在一行并且将用于我们的目的。
答案 5 :(得分:0)
使用循环中的“for cursor 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;