在where子句中的最大id上左联接

时间:2018-07-31 14:29:14

标签: sql oracle oracle11g

我正在使用一个有点复杂的数据库架构来描述一个人及其联系人(电子邮件/地址/电话/等),可以将其简化为以下内容

create table person(
 person_id number,
  name varchar2(25)
)

create table contact(
  contact_id number,
  person_id number,
  contact_type number
)

create table address(
  contact_id number,
  street varchar2(50),
  state varchar2(2),
  primary_ind char(1)
)

create table email(
  contact_id number,
  email_addr varchar2(50),
  primary_ind char(1)
)

我要写的查询的内容是该行的max(contact_id)primary_ind的每个联系人的'Y',如果不存在这样的记录,我希望结果为为空。我有这样一种查询,但是,如果没有行带有主要指示符,则即使左联接,该人也将从结果中完全排除。可以在以下网址找到示例小提琴

SQLFiddle

查询:

select
 p.name,
 a.street,
 e.email_addr
from person p
left outer join contact ca
on ca.person_id = p.person_id
and ca.contact_type = 1
left outer join address a
on a.contact_id = ca.contact_id
and a.primary_ind = 'Y'
left outer join contact ce
on ce.person_id = p.person_id
and ce.contact_type = 2
left outer join email e
on e.contact_id = ce.contact_id
and e.primary_ind = 'Y'
where
(ca.contact_id = (select max(cma.contact_id) from contact cma inner join address am on cma.contact_id = am.contact_id where am.primary_ind = 'Y' and cma.person_id = p.person_id and cma.contact_type = 1) or ca.contact_id is null)
and (ce.contact_id = (select max(cme.contact_id) from contact cme inner join email em on cme.contact_id = em.contact_id where em.primary_ind = 'Y' and cme.person_id = p.person_id and cme.contact_type = 2) or ce.contact_id is null);

我希望看到的结果是

|-------------------------------------------------------------|
| NAME      | STREET                | EMAIL_ADDR              |
| Bill Ted  | Bills Primary Address | billprimary@example.com |
| Bob Dole  | Bobs Primary Address  | (null)                  |
|-------------------------------------------------------------|

但是,由于Bob记录仅包含非主要电子邮件地址,因此我的查询似乎以某种方式将其排除在外。该模式已经定型,更改它会非常具有侵入性。

1 个答案:

答案 0 :(得分:1)

我对您的代码进行了一些编辑:

SELECT p.name, a.street, e.email_addr
  FROM person p
       LEFT OUTER JOIN (SELECT *
                          FROM contact ca
                         WHERE     (  (ca.contact_id, ca.person_id) IN (SELECT MAX(cma.contact_id), cma.person_id
                                                                          FROM contact cma
                                                                          JOIN person p ON (cma.person_id = p.person_id)
                                                                    INNER JOIN address am ON cma.contact_id = am.contact_id
                                                                         WHERE am.primary_ind = 'Y' AND cma.contact_type = 1
                                                                         GROUP BY cma.person_id)
                                    OR ca.contact_id IS NULL)
                               AND ca.contact_type = 1) ca2
           ON ca2.person_id = p.person_id
       LEFT OUTER JOIN address a ON a.contact_id = ca2.contact_id AND a.primary_ind =     'Y'
       LEFT OUTER JOIN (SELECT *
                          FROM contact ce
                         WHERE     (  (ce.contact_id, ce.person_id) IN (SELECT MAX(cme.contact_id), cme.person_id
                                                                          FROM contact cme
                                                                          JOIN person p ON (cme.person_id = p.person_id)
                                                                    INNER JOIN email em ON cme.contact_id = em.contact_id
                                                                         WHERE em.primary_ind = 'Y' AND cme.contact_type = 2
                                                                         GROUP BY cme.person_id)
                                    OR ce.contact_id IS NULL)
                               AND ce.contact_type = 2) ce2
           ON ce2.person_id = p.person_id
       LEFT OUTER JOIN email e ON e.contact_id = ce2.contact_id AND e.primary_ind =     'Y'

我所做的是:我将您离开外部联接的引用表从外部WHERE子句移到了内部WHERE子句,从而使它们能够按您的想象进行联接(如LEFT OUTER)。 当我们添加带有左外部联接的where子句时,其行为类似于内部联接

因此,我还必须通过在子查询中使用该表的附加联接来引用该子查询中的 person 表-然后,其中的子句由比较 contact_id,person_id 组合。

请检查结果,并按预期方式提供反馈意见。

相关问题