我有3个学生表,注册表和课程。我想列出每个学生和每个班级的部门代码(部门代码在课堂上)包括未参加任何课程的学生(在这种情况下,部门代码将是空白的)。这是必要的,因为将来的计算将会完成。
以下是我对此的看法。以下查询执行学生和注册的左连接,以便我包括尚未注册任何课程的学生
select s.B#, s.firstname, e.classid
from students s, enrollments e
where s.B#=e.B#(+)
此查询按预期工作。
接下来,我加入了注册和课程,以便我可以看到每个注册的相应dept_code:
select B#, dept_code
from enrollments natural join classes
这也按预期工作。
当我尝试将两者结合在一起时,我遇到了问题
select s.B#, s.firstname, dept_code
from students s, (enrollments e natural join classes)
where s.B# = e.B#(+)
尝试运行此查询时出现错误:
ORA-25156: old style outer join (+) cannot be used with ANSI joins
有人可以解释一下这里发生了什么吗?
答案 0 :(得分:2)
最好使用显式JOIN
而不是使用where子句的旧式逗号分隔连接。同样适用于(+)
。
改为编写您的查询:
select s.B#, s.firstname, dept_code
from students s
left join (
select * -- if there are same names of columns in both tables, specify them explicitly
from enrollments e
join classes c on e.? = c.? -- specify here your natural join columns
) e on s.B# = e.B#
顺便说一句,错误告诉您确切地说,您无法将旧样式连接与ANSI连接组合在一起。可能是时候切换到现在存在很长时间的新格式了。
答案 1 :(得分:1)
支架并不是真的需要,我把它们放在那里只是为了强调结构
select s.B#, s.firstname, c.dept_code
from students s
left join ( enrollments e
join classes c
on c.classId = e.classId
)
on s.B# = e.B3
;
也可能这样写(只有不同的格式)
select s.B#, s.firstname, c.dept_code
from students s
left join enrollments e
join classes c
on c.classId = e.classId
on s.B# = e.B3
;
P.S。 如果您对此语法有疑问,可以尝试这样做:
create table t1 (i int);
create table t2 (i int);
create table t3 (i int);
create table t4 (i int);
create table t5 (i int);
insert into t1 (i) values (1);
insert into t2 (i) values (1);
insert into t3 (i) values (1);
insert into t4 (i) values (1);
insert into t5 (i) values (1);
select *
from t1
join t2
join t3
join t4
join t5
on t5.i=t4.i
on t4.i=t3.i
on t3.i=t2.i
on t2.i=t1.i
;
答案 2 :(得分:0)
您的查询应如下所示:
select s.B#, s.firstname, c.dept_code
from students s left join
enrollments e
on s.B# = e.B3 left join
classes c
on e.classId = b.classId; -- I am guessing what the `JOIN` column is
换句话说,您需要两个left join
来保留所有学生。否则,on
子句可能会过滤掉行。
我也强烈建议你避免和不学习NATURAL JOIN
。这只是代码中等待发生的错误。它仅根据列名匹配列 - 甚至不考虑声明的外键关系。
它隐藏了连接列,这使得调试和理解查询变得更加困难。例如,因为我创建的表几乎总是有CreatedAt
和CreatedBy
等列,所以无法使用它。
编辑:(对于lgrade
)
您可以将条件放在ON
子句中:
select s.B#, s.firstname, c.dept_code
from students s left join
enrollments e
on s.B# = e.B3 and e.lgrade is not null left join
classes c
on e.classId = b.classId; -- I am guessing what the `JOIN` column is
答案 3 :(得分:0)
我强烈建议您避免和取消学习外连接,因为它会产生空值。拥有空值只是代码中等待发生的错误。外连接根本不是一个连接,而是一个'非自然的'联合,使用空值来强制一起。
建议的替代方法:使用适当的默认值自己进行联合:
select B#, firstname, dept_code
from students
natural join enrollments
natural join classes
union
select B#, firstname, '{{NONE}}' as dept_code
from students
where B# not in ( select B# from enrollments );