Нужно внутреннее и внешнее соединение в одной функции - PullRequest
1 голос
/ 29 ноября 2011

У меня есть одна таблица, в которой содержится запись для каждого клиента (основная таблица). Затем у меня есть таблица с дополнительной информацией для некоторых клиентов. В таблице дополнительных сведений иногда нет записей для записи в основной таблице. Иногда в таблице подробностей имеется несколько записей для записи в основной таблице, и в этом случае мне нужна самая последняя запись (отсюда максимальный подвыбор).

Беда в том, что моя функция возвращает значения только для нескольких записей в таблице подробностей. Если я закомментирую часть функции, которая просматривает подробную таблицу, и просто верну значение STAT3, то оно, похоже, будет работать. Как сделать так, чтобы второй выбранный ниже статут применялся, только если есть результат для этого запроса?

create or replace FUNCTION           "F_RETURN_STAT" (
N_UNIQUE IN NUMBER)
RETURN VARCHAR2
IS
V_STAT3 varchar2(20);
V_STAT varchar2(20);
V_STAT2 varchar2(20);
D_ACTDATE date;
D_STARTDATE date;

BEGIN
select expire into D_ACTDATE
from main_table a
where a.uniquefield = N_UNIQUE;
IF 
D_ACTDATE > SYSDATE
or 
D_ACTDATE is null
then
V_STAT :='TRUE';
else 
v_STAT :='FALSE';
end if;


select b.startdate into D_STARTDATE
from main_table a, detail_table b
where a.uniquefield= b.main_table_id(+) and
b.main_table_id = N_UNIQUE and
b.uniquefield in 
  (select max(c.uniquefield) from detail_table c  group by main_table_id);
if 
D_STARTDATE is not null
 then
V_STAT2 :='FALSE';
  end if;

    if 
 V_STAT2 ='FALSE'
        then
        V_STAT3 :='FALSE';
        ELSE
 V_STAT3 := V_STAT;
        end if ;
RETURN(V_STAT3);
end;

Ответы [ 2 ]

1 голос
/ 29 ноября 2011

Я думаю, что эта версия вашей функции решит вашу проблему:

CREATE OR REPLACE FUNCTION f_return_stat(n_unique IN NUMBER)
   RETURN VARCHAR2 IS
   v_stat3     VARCHAR2(20);
   v_stat      VARCHAR2(20);
   v_stat2     VARCHAR2(20);
   d_actdate   DATE;
   d_startdate DATE;
BEGIN
   --First Query
   SELECT expire
   INTO   d_actdate
   FROM   main_table a
   WHERE  a.uniquefield = n_unique;

   IF d_actdate > SYSDATE OR d_actdate IS NULL THEN
      v_stat   := 'TRUE';
   ELSE
      v_stat   := 'FALSE';
   END IF;

   BEGIN
      --Second Query
      SELECT b.startdate
      INTO   d_startdate
      FROM   detail_table b
      WHERE  b.main_table_id = n_unique
         AND b.uniquefield IN (SELECT   MAX(c.uniquefield)
                               FROM     detail_table c
                               GROUP BY main_table_id);
   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         d_startdate   := NULL;
   END;

   IF d_startdate IS NOT NULL THEN
      v_stat2   := 'FALSE';
   END IF;

   IF v_stat2 = 'FALSE' THEN
      v_stat3   := 'FALSE';
   ELSE
      v_stat3   := v_stat;
   END IF;

   RETURN (v_stat3);
END;

В вашей версии второго запроса ваше объединение (a.uniquefield= b.main_table_id) и ваш фильтр (b.main_table_id = N_UNIQUE) эквивалентны,так что main_table a можно удалить вообще.Единственная причина оставить это, чтобы убедиться, что ваш запрос всегда возвращает строку.Если вы используете обработку исключений, чтобы перехватить исключение NO_DATA_FOUND, эта потребность исчезнет, ​​и вы сможете упростить запрос, выбрав из detail_table b.

0 голосов
/ 29 ноября 2011

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

 SELECT b.startdate
 INTO   d_startdate
 FROM   detail_table b
 WHERE  b.main_table_id = n_unique
 and
 (b.uniquefield in 
  (select max(c.uniquefield) from detail_table c  group by main_table_id)
    or b.uniquefield is null);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...