Oracle 在一个函数中需要内部和外部连接

Oracle 在一个函数中需要内部和外部连接,oracle,function,plsql,Oracle,Function,Plsql,我有一个表为每个客户保存一条记录(主表)。然后,我为一些客户准备了一张带有附加细节的表格。附加明细表有时没有主表中记录的记录。有时,对于主表中的一条记录,detail表有多条记录&如果是这种情况,我需要最新的记录(因此需要max subselect) 问题是我的函数只返回细节表中少数记录的值。如果我注释掉函数中查看细节表的部分,只返回STAT3值,它似乎可以工作。如何使下面的第二个select语句仅在该查询有结果时才适用 create or replace FUNCTION

我有一个表为每个客户保存一条记录(主表)。然后,我为一些客户准备了一张带有附加细节的表格。附加明细表有时没有主表中记录的记录。有时,对于主表中的一条记录,detail表有多条记录&如果是这种情况,我需要最新的记录(因此需要max subselect)

问题是我的函数只返回细节表中少数记录的值。如果我注释掉函数中查看细节表的部分,只返回
STAT3
值,它似乎可以工作。如何使下面的第二个select语句仅在该查询有结果时才适用

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;

我相信可能有一种更有效的方法来完成这项工作:

 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);

我相信可能有一种更有效的方法来完成这项工作:

 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);

我认为此版本的函数将解决您的问题:

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\u table\u id
)和过滤器(
b.main\u table\u id=N\u UNIQUE
)是等效的,因此可以完全删除
main\u table a
)。保留它的唯一原因是确保查询始终返回一行。如果您使用异常处理来捕获
NO\u DATA\u FOUND
异常,那么这种需求就会消失,您可以简化查询,只需从
detail\u表b
中进行选择,我认为此版本的函数将解决您的问题:

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\u table\u id
)和过滤器(
b.main\u table\u id=N\u UNIQUE
)是等效的,因此可以完全删除
main\u table a
)。保留它的唯一原因是确保查询始终返回一行。如果您使用异常处理来捕获
NO\u DATA\u FOUND
异常,那么这种需求就消失了,您可以简化查询,只从
detail\u表b

中进行选择,如果您选择的唯一字段将为空,那么进行外部联接有什么意义?即使您完成了这项工作,
D_START_DATE
仍将为空。它并不总是为空。如果函数不为null,则返回“FALSE”。如果为null,则返回第一个查询和第一个if语句的值。很抱歉,如果您必须重新阅读此内容。我已多次更新此注释。我的观点是,如果在查询中使用内部联接还是外部联接,
detail\u表中没有行,您所询问的查询将返回
null
D\u STARTDATE
。或者,如果使用显式游标,至少会这样。实际上,您可以将连接更改为内部连接,并捕获
NO\u ROW\u FOUND
错误,而不是尝试使外部连接工作。啊,好的。。我试着添加一些东西来表示STAT2是否为null,但这不起作用。因此,我猜您必须显式添加一些内容来生成null,否则它只会查看在详细信息表中具有匹配记录的记录?如果您选择的唯一字段都是null,那么进行外部连接有什么意义?即使您完成了这项工作,
D_START_DATE
仍将为空。它并不总是为空。如果函数不为null,则返回“FALSE”。如果为null,则返回第一个查询和第一个if语句的值。很抱歉,如果您必须重新阅读此内容。我已多次更新此注释。我的观点是,如果在查询中使用内部联接还是外部联接,
detail\u表中没有行,您所询问的查询将返回
null
D\u STARTDATE
。或者,如果使用显式游标,至少会这样。实际上,您可以将连接更改为内部连接,并捕获
NO\u ROW\u FOUND
错误,而不是尝试使外部连接工作。啊,好的。。我试着添加一些东西来表示STAT2是否为null,但这不起作用。所以我想你必须显式地添加一些东西来产生空值,否则它只会查看在细节表中有匹配记录的记录?嗯,这给出了一个缺少右括号的错误。我认为这是行不通的,因为如果主表中没有匹配项,查询不会返回null。。。它仅在细节表中有记录时返回结果。它看起来像外部联接,但我认为max子查询强制内部联接。感谢您查看此btwhmmm,这给出了一个缺少右括号的错误。我认为这是行不通的,因为如果主表中没有匹配项,查询不会返回null。。。它仅在细节表中有记录时返回结果。它看起来像外部联接,但我认为max子查询强制内部联接。谢谢你看这个btw