【问题标题】:PL/SQL using outer joinPL/SQL 使用外连接
【发布时间】:2017-01-10 04:04:09
【问题描述】:

我有 3 张桌子:

  • A(t_ref 整数,l_date 日期),
  • B(t_ref 整数,client_ref 整数),
  • C(t_id 整数,client_ref 整数)
    和参数(client_ref_ integer)。

我需要从表 A 中选择具有条件的数据:
1)如果表B中有行与client_ref相连(如果查询

select b.t_ref from B b where b.client_ref = client_ref_ 

返回任何数据),我的查询将如下所示:

select max(l_date) from A where t_ref in (select b.t_ref from B b where b.client_ref = client_ref_)

2) 如果上面的查询返回任何数据,我的查询将如下所示:

 select max(l_date) from A where t_ref in (select c.t_id from C c where c.client_ref = client_ref_)

现在我写了一个 PLSQL 函数:

  select max(aa.l_date) into l_date from A aa where aa.t_ref in (select bb.t_ref from B bb where bb.client_ref = client_ref_);
  if l_date is null then
    select max(aa.l_date) into l_date from A aa where t_ref in (select t_id from C c where c.client_ref = client_ref_);
  end if;
return l_date;

它有效,但这不是一个好主意,因为我调用了表 A 2 次。是否可以避免第二次调用,并在一个查询中执行此操作?

【问题讨论】:

  • 在您的函数中,第一个选择将失败。您已将表别名为 aa 并在选择查询中使用单个 a。 max(a.l_date) 到 l_date
  • 对不起,这是 typinq 错误。但这不是主要问题。

标签: sql oracle plsql outer-join


【解决方案1】:

您可以使用这种方式:我在这里介绍了您的所有情况。请验证

create  table A (t_ref integer, l_date date);

create   table B (t_ref integer, client_ref integer);

create   table C (t_id integer, client_ref integer);



 SQL> select * from a
  2  /

     T_REF L_DATE
---------- ---------
        10 01-JAN-11
        20 02-FEB-11
        30 02-MAR-11

SQL> select * from b;

     T_REF CLIENT_REF
---------- ----------
        10        101
        20        102

SQL> select * from c;

      T_ID CLIENT_REF
---------- ----------
        10        101
        20        102
        30        101
        40        103




sql> select max(aa.l_date) 
    --into l_date 
    from A aa 
    where aa.t_ref =any(   case when ( select bb.t_ref from B bb where bb.client_ref = '101' and rownum <2 ) is null then
                                     ( select t_id from C c where c.client_ref = '101' )
                                     when  ( select t_id from C c where c.client_ref = '101' and rownum <2 ) is not null then
                                      ( select t_id from C c where c.client_ref = '101' and rownum <2   )
                                      else
                                     ( select bb.t_ref from B bb where bb.client_ref = '101' )
                                     end
                         );

MAX(AA.L_
---------
01-JAN-11



SQL> select max(aa.l_date) 
--into l_date 
from A aa 
where aa.t_ref =any(   case when ( select bb.t_ref from B bb where bb.client_ref = '102' and rownum <2 ) is null then
                                 ( select t_id from C c where c.client_ref = '102' )
                                 when  ( select t_id from C c where c.client_ref = '102' and rownum <2 ) is not null then
                                      ( select t_id from C c where c.client_ref = '102'   )
                                  else
                                 ( select bb.t_ref from B bb where bb.client_ref = '102' )
                                     end
                     );

MAX(AA.L_
---------
02-FEB-11


SQL> select max(aa.l_date) 
--into l_date 
from A aa 
where aa.t_ref =any(   case when ( select bb.t_ref from B bb where bb.client_ref = '103' and rownum <2 ) is null then
                                 ( select t_id from C c where c.client_ref = '103' )
                                 when  ( select t_id from C c where c.client_ref = '103' and rownum <2 ) is not null then
                                  ( select t_id from C c where c.client_ref = '103'  )
                                  else
                                 ( select bb.t_ref from B bb where bb.client_ref = '103' )
                                     end
                     );

MAX(AA.L_
---------


SQL> 

【讨论】:

  • 返回错误:单行子查询返回多行。
  • 你能分享一些你的表 a,b,c 的示例数据
  • A: ((10, '01.01.2011'), (20, '02.02.2011'), (30, '02.03.2011'), (40, '04.04.2011') ) B: ((10, 101), (20, 102)) C: ((10, 101), (20, 102), (30, 101), (40, 103))。
  • 如果我为客户端 101 执行我的函数,它将返回 01.01.2011,因为表 B 中有一条与客户端 101 连接的记录。如果我将我的函数调用到客户端 102,它将返回 02.02 .2011.如果我为客户端103调用我的函数,它将返回04.04.2011,因为表B中没有与104客户端连接的记录,但表C中有这样的记录。
  • 如果我在您的数据集为空白的情况下运行我的查询..不会给出任何错误..您尝试使用您提供的数据运行查询并检查是否有任何错误
【解决方案2】:

试试这个。

select max(aa.l_date) into l_date from A aa 
    where t_ref in 
    (SELECT t_ref from (select t_id t_ref,client_ref_ client_ref_ from C c
                          UNION
                        select t_ref t_ref,client_ref_ client_ref_ from B b) 
                       tmp where tmp.client_ref = client_ref_)
return l_date;

【讨论】:

  • 我不需要 UNION。在任何情况下,它将返回来自 C 的所有记录和来自 B 的所有与 client_ref_ 连接的记录,但如果它们存在,我需要来自 B 的记录,如果它们不存在,我需要来自 C 的记录。
  • 存在是什么意思.. 能否分享所有 3 个表中的示例数据。
  • 如果表 B 中有行与client_ref_ 连接,我需要它们。如果B中没有与client_ref_相连的行,我需要从C中选择与client_ref_相连的所有行
【解决方案3】:
with
     prep ( t_ref, idx ) as (
       select  b.t_ref, 1
         from  table_B b 
         where b.client_ref = :client_ref 
       union all
       select  c.t_ref, 2
         from  table_C c 
         where c.client_ref = :client_ref 
     )
select max(a.l_date) keep (dense_rank first order by p.idx) -- into l_date
from   table_A a inner join prep p
                 on a.t_ref = p.t_ref
;

解释:首先扫描table_B 寻找匹配client_ref 的行;如果找到,请收集它们并附上1 的“索引”。然后扫描table_C 并执行相同操作,但使用索引2。 (如果table_C 非常大,那么在table_B 中找到:client_ref 是浪费时间;如果这是一个问题,可以用更多代码来解决)。然后table_A 加入到将这两组行放在一起的结果中。 keep dense_rank first... 将确保 max(l_date) 只考虑带有idx = 1 的行,但如果不存在这样的行,则只考虑带有 idx = 2 的行。

如果在表 B 和表 C 中都没有找到 :client_ref,则生成的 max(l_date) 将是 null

我使用:clent_ref 作为绑定变量编写了查询,因此我可以测试查询;你可以把它改成你的变量名client_ref_

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多