这是设置 -
create table tasks (taskno int, customerno int);
insert into tasks values (1, 100);
commit;
insert into tasks values (2, 200);
commit;
insert into tasks values (3, 300);
commit;
select * from tasks;
create table items (taskno int, accountno int);
commit;
insert into items values (1, 1000);
commit;
insert into items values (2, 2000);
commit;
select * from items;
create table accounts (accountno int, customerno int);
commit;
insert into accounts values (1000, 100);
commit;
insert into accounts values (1100, 100);
commit;
insert into accounts values (2000, 200);
commit;
insert into accounts values (3000, 300);
commit;
select * from accounts;
我想根据accountno从task表中获取taskno。任务表只有一个名为customerno的东西。此customerno可以与多个accountno相关联(将customerno视为父级,将accountno视为子级)。因此,如果您查看我们的设置,如果我传入accountno 1000或1100,则在此查询中都将返回taskno 1 -
select a.taskno
from tasks a, accounts c
where a.customerno = c.customerno
and c.accountno = 1000 -- but will return taskno 1 also for 1100
我想要一些比这更详细的细节。所以我找到了另一张桌子' Items'其中有taskno和accountno。因此,如果我将其添加到查询中,它将正确返回accountno 1000的taskno 1而不是1100.
select a.taskno
from tasks a, items b, accounts c
where a.taskno = b.taskno
and a.customerno = c.customerno
and c.accountno = b.accountno
and c.accountno = 1000 -- nothing returned for 1100
这一切都很好但是Items表并不总是可靠的。它可以说约占任务表中90%的任务。因此,在这种情况下,当在Items表中找不到任务时,我希望它来自Tasks表,例如accountno 3000(这意味着我将不得不通过customerno,并且不会具有粒度级别的accountno join。但是没关系) 。但是当在Items中找到这个accountno时,我希望它被使用,因为它有accountno,这给了我与完全accountno相关联的taskno。所以我对包含任务的Items使用左外连接。
这完美无缺 -
select a.taskno
from tasks a, items b, accounts c
where a.taskno = b.taskno(+)
and a.customerno = c.customerno
and c.accountno = nvl(b.accountno, c.accountno)
and c.accountno = 3000 -- will return taskno 3
select a.taskno
from tasks a, items b, accounts c
where a.taskno = b.taskno(+)
and a.customerno = c.customerno
and c.accountno = nvl(b.accountno, c.accountno)
and c.accountno = 1000 --returns 1 and nothing returned for 1100
我的问题是我在这里正确构建了查询 - 特别是我用NVL将项目链接到帐户的部分?这是预期的方法吗?或者这是一个奇怪的回合路?
答案 0 :(得分:1)
就像你说的那样,你的查询确实有效,并且非常聪明。但是很难阅读和理解,部分原因是因为使用了连接语法。使用ANSI连接进行翻译,我们得到:
select t.taskno
from accounts a
join tasks t
on t.customerno = a.customerno
left join items i
on i.taskno = t.taskno
where a.accountno = 1100
and a.accountno = nvl(i.accountno, a.accountno)
我仍然觉得意图不是很清楚。
就个人而言,我会重写查询,将左连接的逻辑移到not exists
子句中。在我看来,它更好地表达了意图,并且它的效果也一样。
在ANSI连接语法中:
select t.taskno
from accounts a
join tasks t
on t.customerno = a.customerno
where a.accountno = 1100
and not exists (select null
from items i
where i.taskno = t.taskno
and i.accountno <> a.accountno)
旧版连接语法中的相同查询,如果它可以帮助您更好地理解(但如果可能的话,尝试远离此语法):
select t.taskno
from accounts a, tasks t
where a.accountno = 1100
and t.customerno = a.customerno
and not exists (select null
from items i
where i.taskno = t.taskno
and i.accountno <> a.accountno)