Процедура Oracle: прочитать из таблицы A и, если не найдено, перейти к таблице B.

Я хочу прочитать данные либо из таблицы A, либо из таблицы B. Моя база данных - оракул, и процедура должна использовать минимальное количество запросов. Требуется прочитать из одной таблицы, а если данные недоступны, перейти к другой таблице. Я написал следующую процедуру,

CREATE OR REPLACE PROCEDURE READ(myId IN VARCHAR2, aout OUT   SYS_REFCURSOR,  bout OUT SYS_REFCURSOR )
  IS
  temp_acout_type A_TABLE%ROWTYPE;
  BEGIN
     OPEN aout FOR SELECT * FROM A_TABLE WHERE ID = myId;
     FETCH aout into temp_acout_type ;
     if aout%NOTFOUND then
        OPEN bout FOR SELECT * FROM B_TABLE WHERE ID = myId;
     end if;
 END;

Я вызываю эту функцию со стороны Java. Моя проблема в том, что когда я получаю курсор в процедуре, курсор теряет данные. Я наблюдал это с Java-клиента, так как ResultSetin java-сторона пуста (запросы в процедуре будут иметь только 1 запись, так как она ищет по первичному ключу), хотя она должна содержать данные.

Мне нужен способ реализовать вышеуказанную логику, но без использования дополнительных запросов (например: данные первой проверки доступны в таблице A). Есть ли способ сделать это ?


person Viraj    schedule 24.03.2015    source источник


Ответы (2)


Вы всегда можете открыть оба курсора в хранимой процедуре PL/SQL, а затем в Java, получить данные из первого, а затем только из второго, если вы не получили данные из первого. Это предотвратило бы ненужные чтения (открытие курсора не приводит к чтению; он устанавливает путь выполнения, готовый к тому моменту, когда вы хотите получить данные).

В качестве альтернативы вы можете объединить все две таблицы и выбрать только первую строку (где первая означает, что из первого запроса есть данные).

person Boneist    schedule 24.03.2015

Проверьте количество строк в таблице. Вы можете использовать предложение ограничивающего строки, например ROWNUM или FETCH в 12c.

Поскольку вы говорите, что идентификатор является первичным ключом, поэтому он будет извлекать только 1 строку, просто сделайте это так:

SELECT COUNT(*) INTO var_cnt FROM A_TABLE WHERE ID = myId;

IF var_cnt > 0
THEN 
   OPEN aout FOR SELECT * FROM A_TABLE WHERE ID = myId;
ELSE
   OPEN bout FOR SELECT * FROM B_TABLE WHERE ID = myId;
END IF;

Однако вы не можете быть уверены, что извлекаемая строка точно будет в наборе результатов курсора, так как тем временем какой-то другой сеанс может УДАЛИТЬ строку перед оператором OPEN FOR выполняется.

Для здравого смысла я бы посоветовал использовать аналитический COUNT() OVER() в запросе явный курсор.

person Lalit Kumar B    schedule 24.03.2015
comment
Есть ли возможность использовать только два основных запроса на выборку, каким-то образом опуская select count(*)? - person Viraj; 24.03.2015
comment
Да, используя count() over(). Затем вы будете подсчитывать строки в том же запросе. - person Lalit Kumar B; 24.03.2015