PL/SQL 使用外连接
PL/SQL using outer join
我有 3 个 table:
- A(t_ref整数,l_date日期),
- B(t_ref整数,客户t_ref整数),
- C(t_id整数,客户t_ref整数)
和参数(客户端t_ref_整数)。
我需要 select 来自 table A 的数据,条件为:
1)如果tableB中有行与client_ref连接(如果查询
select b.t_ref from B b where b.client_ref = client_ref_
returns 任何数据),我的查询将如下所示:
select max(l_date) from A where t_ref in (select b.t_ref from B b where b.client_ref = client_ref_)
2) 如果查询上面 returns 任何数据,我的查询将是这样的:
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;
可行,但这不是个好主意,因为我调用了 table A 2 次。是否可以避免第二次调用,并在一次查询中执行此操作?
您可以使用这种方式:我在这里介绍了您的所有情况。请验证
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>
试试这个。
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;
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
的行;如果找到任何东西,请收集它们并附上 "index" 的 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_
我有 3 个 table:
- A(t_ref整数,l_date日期),
- B(t_ref整数,客户t_ref整数),
- C(t_id整数,客户t_ref整数)
和参数(客户端t_ref_整数)。
我需要 select 来自 table A 的数据,条件为:
1)如果tableB中有行与client_ref连接(如果查询
select b.t_ref from B b where b.client_ref = client_ref_
returns 任何数据),我的查询将如下所示:
select max(l_date) from A where t_ref in (select b.t_ref from B b where b.client_ref = client_ref_)
2) 如果查询上面 returns 任何数据,我的查询将是这样的:
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;
可行,但这不是个好主意,因为我调用了 table A 2 次。是否可以避免第二次调用,并在一次查询中执行此操作?
您可以使用这种方式:我在这里介绍了您的所有情况。请验证
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>
试试这个。
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;
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
的行;如果找到任何东西,请收集它们并附上 "index" 的 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_