连接4个表

时间:2014-11-08 15:42:24

标签: sql database oracle oracle-sqldeveloper

我只是SQL的初学者,我遇到了无法解决的问题。

问题如下:

我有四张桌子

Student: matrnr, name, semester, start_date
Listening: matrnr<Student>, vorlnr<Subject>
Subject: vorlnr, title, sws, teacher<Professor>
Professor: persnr, name, rank, room

我需要列出所有正在聆听某位教授主题的学生的名字。

编辑:

select s.* 
from Student s, Listening h
where s.matrnr=h.matrnr
and h.vorlnr in (select v.vorlnr from Subject v, Professor p                        
where v.gelesenvon=p.persnr and p.name='Kant');

这就是我解决它的方法,但我不确定它是否是最佳解决方案。

4 个答案:

答案 0 :(得分:3)

你的方法很好。只是,你想向学生展示,但是让学生加入列表,从而获得学生列表组合。

此外,您使用过时的连接语法。二十多年前它被明确的连接(INNER JOIN,CROSS JOIN等)取代了。

您只能使用子查询来执行此操作:

select * 
from Students, 
where matrnr in 
(
  select matrnr
  from Listening
  where vorlnr in
  (
    select vorlnr 
    from Subject
    where gelesenvon in
    (
      select persnr
      from Professor
      where name='Kant'
    )
  )
);

或加入其他表:

select * 
from Students 
where matrnr in 
(
  select l.matrnr
  from Listening l
  inner join Subject s on s.vorlnr = l.vorlnr
  inner join Professor p on p.persnr = s.gelesenvon and p.name='Kant'
);

或者使用EXISTS:

select * 
from Students s 
where exists
(
  select *
  from Listening l
  inner join Subject su on su.vorlnr = l.vorlnr
  inner join Professor p on p.persnr = su.gelesenvon and p.name='Kant'
  where l.matrnr = s.matrnr
);

有些人喜欢加入everthing,然后使用DISTINCT进行清理。这很容易编写,特别是因为您不必首先考虑您的查询。但出于同样的原因,当涉及更多表格和更多逻辑时(如聚合),它会变得复杂,并且它也会变得非常难以阅读。

select distinct s.* 
from Students s 
inner join Listening l on l.matrnr = s.matrnr
inner join Subject su on su.vorlnr = l.vorlnr
inner join Professor p on p.persnr = su.gelesenvon and p.name='Kant';

最后这是一个品味问题。

答案 1 :(得分:3)

当您遇到SQL问题时,提出问题的一种好方法是将表格显示为CREATE TABLE语句。此类语句显示详细信息,例如列的类型以及哪些列是主键。此外,这使我们能够实际构建一个小型数据库,以便重现错误行为或仅测试我们的解决方案。

CREATE TABLE Student
(
    matrnr NUMBER(9) PRIMARY KEY,
    name NVARCHAR2(50),
    semester NUMBER(2),
    start_date DATE
);

CREATE TABLE Listening
(
    matrnr NUMBER(9), -- Student
    vorlnr NUMBER(9), -- Subject
    CONSTRAINT PK_Listening PRIMARY KEY (matrnr, vorlnr)
);

CREATE TABLE Subject
(
    vorlnr NUMBER(9) PRIMARY KEY,
    title NVARCHAR2(50),
    sws NVARCHAR2(50),
    teacher NUMBER(9) -- Professor
);

CREATE TABLE Professor
(
    persnr NUMBER(9) PRIMARY KEY,
    name NVARCHAR2(50),
    rank NUMBER(3),
    room NVARCHAR2(50)
);

使用此架构,我的解决方案如下所示:

SELECT *
FROM
    Student
WHERE
    matrnr IN (
        SELECT L.matrnr
        FROM
            Listening L
            INNER JOIN Subject S
                ON L.vorlnr = S.vorlnr
            INNER JOIN Professor P
                ON S.teacher = P.persnr
        WHERE P.name = 'Kant'
    );

你可以在这里找到它:http://sqlfiddle.com/#!4/5179dc/2
由于我没有插入任何记录,因此它唯一测试的是语法和正确使用表名和列名。

您的解决方案不是最理想的。它不区分表的连接和指定为where子句的附加条件。如果他们参加教授的几门课程,它可以为每个学生产生几个结果记录。因此,我的解决方案将所有其他表放入子选择。

答案 2 :(得分:2)

select st.name
from student st
join listening l on l.matrnr = st.matrnr
join subject su on su.vorlnr = l.vorlnr
join professor p on su.teacher = p.persnr
where p.name = 'some name'

答案 3 :(得分:1)

SELECT * 
FROM student 
INNER JOIN listening ON student.matrnr = listening.matrnr
INNER JOIN subject ON listening.vorlnr = subject.vorlnr
INNER JOIN professor ON subject.teacher = professor.name
WHERE professor.name = 'some name'