这是一种可接受的加入方式(左外部加入 table)吗?
Is this an accepted way to join (left outer join table)?
这里是设置-
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;
我想根据一个帐号从任务 table 中获取任务号。任务 table 只有一个叫做 customerno 的东西。此 customerno 可以与多个 accountno 关联(将 customerno 视为父级,将 accountno 视为子级)。因此,如果您查看我们的设置,如果我传入 accountno 1000 或 1100,则此查询中的 return 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
我想要比这更详细的细节。所以我找到了另一个 table 'Items',它有 taskno 和 accountno。因此,如果我将它添加到查询中,它将正确地 return taskno 1 用于 accountno 1000 而不是 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
这一切都很好,但项目 table 并不总是可靠的。它可以说只有 90% 的任务在任务 table 中找到。因此,在这种情况下,当在项目 table 中找不到任务时,我希望从任务 table 中找到它,例如 accountno 3000(这意味着我将不得不通过 customerno 并且不会有粒度级别帐户没有加入。但没关系)。但是当在 Items 中找到这个 accountno 时,我希望它被使用,因为它有 accountno,这给了我与确切的 accountno 关联的任务号。因此,我将左外连接用于带有任务的项目。
这很完美-
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 将项目链接到帐户的部分?这是执行此操作的预期方法吗?或者这是一个奇怪的循环方式?
正如您所说,您的查询确实有效,而且非常聪明。但它很难阅读和理解,部分原因在于所使用的连接语法。使用 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)
这里是设置-
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;
我想根据一个帐号从任务 table 中获取任务号。任务 table 只有一个叫做 customerno 的东西。此 customerno 可以与多个 accountno 关联(将 customerno 视为父级,将 accountno 视为子级)。因此,如果您查看我们的设置,如果我传入 accountno 1000 或 1100,则此查询中的 return 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
我想要比这更详细的细节。所以我找到了另一个 table 'Items',它有 taskno 和 accountno。因此,如果我将它添加到查询中,它将正确地 return taskno 1 用于 accountno 1000 而不是 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
这一切都很好,但项目 table 并不总是可靠的。它可以说只有 90% 的任务在任务 table 中找到。因此,在这种情况下,当在项目 table 中找不到任务时,我希望从任务 table 中找到它,例如 accountno 3000(这意味着我将不得不通过 customerno 并且不会有粒度级别帐户没有加入。但没关系)。但是当在 Items 中找到这个 accountno 时,我希望它被使用,因为它有 accountno,这给了我与确切的 accountno 关联的任务号。因此,我将左外连接用于带有任务的项目。
这很完美-
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 将项目链接到帐户的部分?这是执行此操作的预期方法吗?或者这是一个奇怪的循环方式?
正如您所说,您的查询确实有效,而且非常聪明。但它很难阅读和理解,部分原因在于所使用的连接语法。使用 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)