我正在使用一个有点复杂的数据库架构来描述一个人及其联系人(电子邮件/地址/电话/等),可以将其简化为以下内容
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'
,如果不存在这样的记录,我希望结果为为空。我有这样一种查询,但是,如果没有行带有主要指示符,则即使左联接,该人也将从结果中完全排除。可以在以下网址找到示例小提琴
查询:
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记录仅包含非主要电子邮件地址,因此我的查询似乎以某种方式将其排除在外。该模式已经定型,更改它会非常具有侵入性。
答案 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 组合。
请检查结果,并按预期方式提供反馈意见。