2014-11-08 83 views
2

我只是SQL的初學者,而且我遇到了無法解決的問題。連接4個表

的問題如下:

我有四張桌子

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'); 

這是我如何解決它,但我不知道是不是最佳的解決方案。

回答

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' 
); 

或者與存在:

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 
); 

有些人喜歡加入寄託都,然後在最後清理使用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'; 

最後這是一個味道問題。

+0

第一次看,我更喜歡EXISTS的變體,但正如我在Oracle上看到的,IN和EXISTS在這種情況下都會生成相同的計劃。 – 2014-11-08 16:38:34

+0

@VDohnal:因爲IN和EXISTS會做同樣的事情。特別是在Oracle中,它甚至可以處理像「where(a,b)in(select ...)」這樣的元組,而許多其他dbms不需要。再次,無論選擇IN還是EXISTS,都是一個品味問題。我經常選擇IN;也許是因爲我傾向於分組思考。 – 2014-11-08 17:11:51

+0

'IN'和'EXISTS'非常相似,但它們並不相同 - 不僅在性能方面。當數據包含「NULL」值時,您可以得到不同的結果。在這裏看到一些解釋:[瞭解空值如何影響IN和EXISTS](http://www.techrepublic.com/article/oracle-tip-understand-how-nulls-affect-in-and-exists/)或谷歌的' oracle差異和存在空' – 2014-11-09 08:39:08

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' 
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' 
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子句指定的附加條件。如果他們參加了幾位教授的課程,它可以爲每個學生創造幾個結果記錄。因此,我的解決方案將所有其他表放入子選擇中。