【问题标题】:Need inner and outer join in one function需要内外部连接在一个功能中
【发布时间】:2011-11-28 21:39:51
【问题描述】:

我有一个表,其中包含每个客户的记录(主表)。然后,我为一些客户准备了一张包含更多详细信息的表格。附加明细表有时在主表中没有记录。有时,详细表在主表中有多个记录,如果是这种情况,我需要最近的记录(因此是最大子选择)。

问题是我的函数只返回详细表中少数记录的值。如果我注释掉查看详细信息表的函数部分并仅返回 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;

【问题讨论】:

  • 如果您选择的唯一字段无论哪种方式都为空,那么进行外连接有什么意义?即使您完成了这项工作,D_START_DATE 仍然为空。
  • 它不会总是为空。如果函数不为空,则该函数返回“FALSE”。如果它为空,则返回第一个查询的值和第一个 if 语句。抱歉,如果您不得不重新阅读此内容。我已多次更新此评论
  • 我的意思是,如果detail_table 中没有行,无论您在查询中使用内部联接还是外部联接,您所询问的查询都会将null 返回到D_STARTDATE。或者至少如果您使用的是显式游标,它会。实际上,您可以将联接更改为内部联接并捕获 NO_ROW_FOUND 错误,而不是尝试使外部联接起作用。
  • 啊,好吧..我尝试添加一些东西来影响 STAT2 是否为空,但这不起作用。所以我想你必须明确添加一些东西来产生 null 否则它只会查看在详细表中有匹配记录的记录?

标签: oracle function plsql


【解决方案1】:

我认为这个版本的函数会解决你的问题:

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 中进行选择。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • hmmm 这给出了缺少右括号的错误。而且我认为不会起作用,因为如果主表中没有匹配项,查询不会返回空值......它仅在详细表中有记录时才返回结果。它看起来像一个外部联接,但我认为最大子查询强制内部联接。谢谢你看这个顺便说一句
    猜你喜欢
    • 2020-04-27
    • 2015-01-17
    • 2021-02-26
    • 1970-01-01
    • 2020-02-09
    • 2014-10-16
    • 2014-09-29
    • 1970-01-01
    • 2016-04-27
    相关资源
    最近更新 更多