2012-05-26 131 views
2

選擇兩個表中的一條記錄有三個表:在甲骨文

  1. 對學生的表:關於選擇課程c41071030(cno, cname, cpno, credit)

  2. 一個表:s41071030(sno, sname, ssex, sage, sdept)

  3. 有關課程的表:sc41071030(sno, cno, grade)

現在,我想選擇一個sdept='CS'的學生的詳細信息,他或她選擇了部門'CS'中的最多課程。

+1

連接和聚合函數(這些都是你應該谷歌而言)會做的伎倆排名中選擇行。 – Anton

+0

+1,用於在問題中包含表名和模式。 –

回答

0

雖然沒有經過測試,但是與您所尋找的東西類似。

select s.* 
from s41071030 s join sc41071030 sc on s.sno = sc.sno 
where s.sdept = 'CS' and (select count(sc41071030.cno) 
from sc41071030 join c41071030 
on sc41071030.cno = c41071030.cno group by sc41071030.sno) > 1 
+0

不是非常接近需要的東西。 –

1

與任何溫和複雜的SQL語句,最好是做「TDQD」 —測試驅動的查詢設計。從問題的簡單部分開始,將它們構建成更復雜的答案。

要找出多少課程,在CS部門每個學生走,我們寫:

SELECT S.Sno, COUNT(*) NumCourses 
    FROM s41071030 S 
    JOIN sc41071030 SC ON S.Sno = SC.Sno 
WHERE S.Sdept = 'CS' 
GROUP BY S.Sno; 

我們現在需要找到NumCourses的最大價值:

SELECT MAX(NumCourses) MaxCourses 
    FROM (SELECT S.Sno, COUNT(*) NumCourses 
      FROM s41071030 S 
      JOIN sc41071030 SC ON S.Sno = SC.Sno 
     WHERE S.Sdept = 'CS' 
     GROUP BY S.Sno 
     ) 

現在,我們需要將結果與子查詢結合在一起,因此是CTE(公用表表達式)的時間:

WITH N AS 
    (SELECT S.Sno, COUNT(*) NumCourses 
     FROM s41071030 S 
     JOIN sc41071030 SC ON S.Sno = SC.Sno 
     WHERE S.Sdept = 'CS' 
     GROUP BY S.Sno 
    ) 
SELECT N.Sno, 
    FROM N 
    JOIN (SELECT MAX(NumCourses) MaxCourses FROM N) M 
    ON M.MaxCourses = N.NumCourses; 

,我們需要得到學生的詳細信息,所以我們加入一個與學生表:

WITH N AS 
    (SELECT S.Sno, COUNT(*) NumCourses 
     FROM s41071030 S 
     JOIN sc41071030 SC ON S.Sno = SC.Sno 
     WHERE S.Sdept = 'CS' 
     GROUP BY S.Sno 
    ) 
SELECT S.Sno, 
    FROM s41071030 S 
    JOIN N ON N.Sno = S.Sno 
    JOIN (SELECT MAX(NumCourses) MaxCourses FROM N) M 
    ON M.MaxCourses = N.NumCourses; 

未經測試的SQL:你被警告。爲了測試,運行組件查詢,確保您每次都能獲得合理的結果。直到前一個查詢正常工作,才能繼續進行下一個查詢。

請注意,課程表對於您正在解決的查詢而言並不重要。

另請注意,如果發現有幾個學生全部參加相同數量的課程並且該數字是任何學生正在參加的最大數量,則可能會返回多行。 (所以,如果有3名學生服用,每次7門課程,並沒有學生服用超過7門課程,然後你會看到3行的結果集。)

1
  1. 總結sc41071030行,以獲得計數。

  2. 加入結果s41071030到:

    • 濾波器行上sdept;

    • 獲取學生信息;

    • RANK()計數值上的連接行。

  3. 與1

WITH aggregated AS (
    SELECT 
    sno, 
    COUNT(*) AS coursecount 
    FROM sc41071030 
    GROUP BY sno 
), 
ranked AS (
    SELECT 
    s.*, 
    RANK() OVER (ORDER BY agg.coursecount DESC) AS rnk 
    FROM sc41071030 s 
    INNER JOIN aggregated agg 
    WHERE s.sdept = 'CS' 
) 
SELECT 
    sno, 
    sname, 
    ssex, 
    sage, 
    sdept 
FROM ranked 
WHERE rnk = 1 
+0

@Jonathan Leffler:Re:在CTE中過濾的好處 - 我選擇在CTE中進行過濾,因爲這樣就不需要對整個'sc41071030'表進行排序(通過'sdept'對錶進行劃分),這可能會更有效。當然,如果sdept過濾器在主選擇中,優化器可能會發現不需要將RANK應用於所有行,而只應用於與指定的sdept匹配的那些行,但是我不能確定。而且我也讓我無需寫出'PARTITION BY ...'。 :) –