Вы можете добавить проверку not exists
к основной таблице как часть ветви архива:
select o.status_code,o.order_id
from order o
where o.order_id=p_order_id
union all
select a.status_code,a.order_id
from order_archive a
where a.order_id=p_order_id
and not exists (
select *
from order o
where o.order_id=p_order_id
);
что теперь, конечно, означает, что он будет смотреть на главную таблицу в обеих ветвях; но это может все же быть быстрее, в зависимости от ваших данных, индексов, статистики и т. д.
Другой вариант, который предотвращает просмотр архивной таблицы при наличии идентификатора в основной таблице, - это сначала сделать простой подсчет по основной таблице, а затем условно открыть курсор ref для одного из двух возможных запросов к один стол каждый; то есть ветвление в PL / SQL, а не в SQL, полностью устраняя объединение. Что-то вроде:
procedure status(p_order_id in varchar2, p_stat out sys_refcursor) is
l_count pls_integer;
begin
select count(*) into l_count
from order o
where o.order_id=p_order_id;
if l_count > 0 then
-- exists in main table so only query that
open p_stat for
select o.status_code,o.order_id
from order o
where o.order_id=p_order_id;
else
-- does not exist in main table so only query archive
open p_stat for
select a.status_code,a.order_id
from order_archive a
where a.order_id=p_order_id;
end if;
end status;
/
Если идентификатор не является уникальным в основной таблице, вы можете добавить and rownum = 1
к исходному запросу, чтобы он останавливался, как только обнаруживал какие-либо подходящие строки (и, следовательно, l_count
может быть не более 1) вместо получить точный подсчет, так как вы на самом деле не заботитесь о фактическом найденном числе.
Можем ли мы использовать выборку и цикл в наборе данных таблицы заказов. Если найдено, то перейдите только к архивной таблице
Не совсем, потому что выборка будет занимать первый ряд результатов. Вот очень надуманный пример:
var rc refcursor;
declare
x varchar2(1);
begin
open :rc for
select 'A' from dual where 1 = 0
union all
select 'B' from dual where 1 = 0;
fetch :rc into x;
if :rc%notfound then
open :rc for select 'C' from dual;
end if;
end;
/
PL/SQL procedure successfully completed.
print rc
'
-
C
При такой настройке основной запрос не находит строк (из-за проверки 1 = 0
); после выборки курсор равен notfound
, поэтому он снова открывает курсор для запроса «архив», и вызывающая сторона видит это, как и ожидалось.
Но если первый запрос возвращает строки:
declare
x varchar2(1);
begin
open :rc for
select 'A' from dual where 1=1
union all
select 'B' from dual where 1=1;
fetch :rc into x;
if :rc%notfound then
open :rc for select 'C' from dual;
end if;
end;
/
PL/SQL procedure successfully completed.
print rc
'
-
B
затем после выборки курсор равен found
, поэтому он не открывает курсор для запроса архива, и существующий курсор ref возвращается обратно вызывающей стороне. Но первая строка из курсора уже была извлечена в переменную x
и потеряна, поэтому вызывающая сторона больше не видит этого. print
показывает только одну строку с 'B'
, а другая строка, которая должна быть там с 'A'
, отсутствует.
Чтобы вызывающая сторона все еще видела обе строки, вам придется заново открыть курсор с помощью основного запроса:
declare
x varchar2(1);
begin
open :rc for
select 'A' from dual where 1=1
union all
select 'B' from dual where 1=1;
fetch :rc into x;
if :rc%found then
open :rc for
select 'A' from dual where 1=1
union all
select 'B' from dual where 1=1;
else
open :rc for select 'C' from dual;
end if;
end;
/
PL/SQL procedure successfully completed.
print rc
'
-
A
B
Логично, что на самом деле это будет то же самое, что и начальный подсчет, который я делаю выше, я полагаю, но будет менее ясным.