1. 程式人生 > >如何以正確地姿勢AK SQL查詢50題(精華篇)

如何以正確地姿勢AK SQL查詢50題(精華篇)

前言------

AK: ALL Killed

這學期學資料庫系統概論,作為一個初學者,必須先熟練掌握SQL的基本查詢語句,在完成了老師的SQL50題之後,我把我自己地AK姿勢記錄下來, 便於回憶之餘,也希望對大家有幫助.

"部落格要精心雕琢,我是米開朗基羅",  雕琢了兩天,然後沒儲存好,實在是太憋屈了,,,不甘心,現在終於補回來了,可以好好睡了.

自認為是SQL50題查詢中最完善的部落格,寫文章不容易啊,終於知道計算機的書籍為啥都這麼貴了....

目錄

一.完成這50題之前首先做什麼?

二.這50題要怎麼做

三.建表並且插入資料

四.給人以魚,不如授之以漁: 題目精選解析

         五.SQL程式碼大全(不包括日期的題目)


一.完成這50題之前首先做什麼?

1.完成第三章的例題

假如你基礎知識還基本沒掌握:我建議先把<< 資料庫系統概論>>(薩師煊)第三章的例題都好好研究一遍, 關鍵是要自己敲一遍, 這樣做的目的是讓你對一些連線,查詢,分組,聚集函式,謂詞查詢,Like,IN,ORDER BY等基礎知識 有足夠的理解和記憶 ,避免做題時,無技巧可用.

2.理解好GROUP BY

分享一篇超好的部落格,一看就領悟(超連結)

3.理解好連線

for(列舉表A中的元組 :i){
    
   for(列舉表B中的元組:j){
   
       for(列舉表C中的元組:k){
         
         if(i ,j,k連線而成的元組滿足條件)
           輸出i,j,k連線而成的元組
       }
  }
}
注:我只是便於理解寫的,實際中,一旦不符合就會contine ,效率比我寫的執行方式高多了

4.把中文輸入法的符號改為英文符號,這絕對能節省一大半的時間

上部分的語句和下部分的語句,差別就在箭頭處的符號是中文字元.......這種錯誤有時很難查詢,會讓你一臉懵逼的,所以建議大家

禁止掉中文符號!!!!!!!! (以搜狗輸入法為例)

 

二.這50題要怎麼做

我覺得這50題當中,比較有價值的題目,或者說稍微有點難度的題目就那麼20題,其餘都是比較基礎的題目.

1.你不能應付作業的形式來對待....要以提升水平來看待

2.在做題的過程中不要去網上查詢題解,這點超級重要!!

3.一道題要儘自己所能去想,時間充足的話,一道題可以給自己一小時的時間去思考,遇到不熟悉的知識,可以翻開課本查詢

4.如果一道題有思路,但是覺得可能不好寫,不要放棄,儘自己所能去模擬出來, 即使你的思路或者解法不是很優秀,但是在你模擬

的中間過程,你獲得了除錯能力,對知識點理解得更加熟練,這比一不會就看答案強多了.

5.實在不會的可以問老師,同學,如果都沒得問的話,可以查詢題解,但是一定要做到是自己的,說白了,不會的這道題,在隔了半個月,你還是會做.

三.建表並且插入資料

環境:PostgreSQL 10 ,命令列模式 (都是用書上基本的SQL語句,可以在mySQL,Sqlite等用)

資料表介紹
--1.學生表
Student(Sno,Sname,Sage,Ssex)
--Sno 學生編號,Sname 學生姓名,Sage 出生年月,Ssex 學生性別
--2.課程表
Course(Cno,Cname,Tno)
--Cno 課程編號,Cname 課程名稱,Tno 教師編號
--3.教師表
Teacher(Tno,Tname)
--Tno 教師編號,Tname 教師姓名
--4.成績表
SC(Sno,Cno,Grade)
--Sno 學生編號,Cno 課程編號,Greade 分數

/*
建立Student表,並且插入資料
*/
CREATE TABLE Student(

   Sno CHAR(9),
   Sname CHAR(9),
   Sage date,
   Ssex CHAR(9)
);
insert into Student values('01' , '趙雷' , '1990-01-01' , '男');
insert into Student values('02' , '錢電' , '1990-12-21' , '男');
insert into Student values('03' , '孫風' , '1990-12-20' , '男');
insert into Student values('04' , '李雲' , '1990-12-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吳蘭' , '1992-01-01' , '女');
insert into Student values('07' , '鄭竹' , '1989-01-01' , '女');
insert into Student values('09' , '張三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2012-06-06' , '女');
insert into Student values('12' , '趙六' , '2013-06-13' , '女');
insert into Student values('13' , '孫七' , '2014-06-01' , '女');
/*
插入Course表和資料
*/

CREATE TABLE Course(

   Cno CHAR(9),
   Cname CHAR(9),
   Tno  CHAR(9)
);

insert into Course values('01' , '語文' , '02');
insert into Course values('02' , '數學' , '01');
insert into Course values('03' , '英語' , '03');
/*
插入Teacher表和資料
*/
CREATE TABLE Teacher(

   Tno CHAR(9),
   Tname CHAR(9)

);

insert into Teacher values('01' , '張三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');

 

/*
建立SC表,並且插入資料
*/
CREATE TABLE SC(

  Sno CHAR(9),
  Cno CHAR(9),
  Grade SMALLINT
);
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);

四.給人以魚,不如授之以漁: 題目精選解析

 

  • 型別一:聚集函式的使用

題目:查詢各科成績最高分、最低分和平均分

SQL程式碼:

SELECT Cno,MAX(Grade) AS 最高分,MIN(Grade) AS 最低分,AVG(Grade) AS 平均分
FROM SC 
GROUP BY Cno;

 

 

  • 型別二:外連線的使用

題目:查詢存在" 01 "課程但可能不存在" 02 "課程的情況(不存在時顯示為 null )

分析:

第一步:先用SC派生出一張只選修01的表 ,x表

第二步:用SC派生出一張只選修02的表,y表

第三步:用x表左外連線y表(題目要求不存在時顯示為NULL),這樣才能保證選修了01課程的學生都可以輸出

SQL程式碼:

SELECT x.*,y.Cno,y.Grade
FROM   (SELECT *
         FROM SC x
         WHERE Cno ='01'
         )  AS x

         LEFT OUTER JOIN 
         ( SELECT *
           FROM SC 
           WHERE Cno ='02'
         ) AS y ON (x.Sno = y.Sno);

 

 

  • 型別三:萬用字元的使用

題目: 查詢名字中含有「風」字的學生資訊

分析: %代表任意個字元

SQL程式碼:

SELECT *
FROM Student
WHERE Sname LIKE '%風%';



 

  • 型別四.巢狀查詢和謂詞IN的使用(優點:結構清晰)

題目:查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績

分析:

第一步:我們依次列舉每個學生,

第二步每當我們列舉一個學生,就應該判斷該該學會是不是屬於"兩門及其以上不及格課程的"的學號集合中;

第三步:所以我們要去找出"兩門及其以上不及格課程的"的學號集合"

第四步:確定了在上述集合中後,我們認定這個學生應該輸出,但是要輸出平均成績怎麼辦呢?在輸出平均成績的時候,在SELECT中計算平均成績,計算後再作為一個屬性輸出.

SQL程式碼:

SELECT Student.*,     (SELECT AVG(Grade)
                       FROM SC
                       WHERE SC.Sno = Student.Sno) AS 平均成績
FROM Student
WHERE Sno IN (
                SELECT Sno
	        FROM  SC 
                WHERE Grade < 60
	        GROUP BY Sno
                HAVING COUNT(Grade) >=2);

 

 

  • 型別五:多欄位分組的使用

題目:按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績(同時要求輸出學生姓名)

分析:

第一步:肯定是拿SC表和Student表按學號進行連線

第二步:考慮分組,那麼按學號分組的話,是無法輸出姓名的,所以考慮多欄位分組,按(Student.Sno ,Sname)進行分組,這樣就可以輸出姓名了

SQL程式碼:

SELECT Student.Sno ,Sname,AVG(Grade) AS 平均成績
FROM SC,Student
WHERE SC.Sno = Student.Sno
GROUP BY Student.Sno ,Sname
ORDER BY 平均成績 DESC;

 

 

  • 型別六:ORDER BY的使用  (DESC是降序,ASC是升序)

注:在PostgreSQL中降序的關鍵字是ASC,在其他關係型資料庫中可能是AESC

題目:檢索" 01 "課程分數小於 60,按分數降序排列的學生資訊

SQL程式碼:

SELECT Student.*,Grade
FROM SC,Student
WHERE Student.Sno = SC.Sno AND  SC.Cno = '01' AND SC.Grade < 60
ORDER BY SC.Grade DESC;

​​​​​​​

 

  • 型別七.EXISTS查詢

  題目:查詢沒學過"張三"老師講授的任一門課程的學生姓名

分析:

第一步: 如果一個學生 x滿足  " 沒學過"張三"老師講授的任一門課程的學生姓名​​​ ",那麼可以等價轉化為什麼條件呢?

第二步:等價條件: 對於學生x,  他選修的所有課程, 肯定"不存在一門課程屬於張三老師講授的課程"

分析完後,我們就可以快速地寫出來了

SQL程式碼:

SELECT Sname    
FROM Student x   
WHERE NOT EXISTS
      (
        SELECT*
        FROM SC y
        WHERE  y.Sno = x.Sno AND  EXISTS
              (
                  SELECT*
                  FROM Teacher,Course
                  WHERE Teacher.Tno = Course.Tno AND y.Cno = Course.Cno  AND Teacher.Tname ='張三' ));

​​​​​​​

 

  • 型別八.EXISTS查詢易錯型別

題目: 查詢和" 01 "號的同學學習的課程 完全相同的其他同學的資訊

分析:這道題有"完全"的字眼,一眼看上去,就想用EXISTS查詢解決,但是後面查詢結果是錯的, 感覺用EXISTS查詢做還是挺容易出錯的

(嘻嘻,也可能是我太菜了~~)

第一步:我們先思考: 如果有個同學 x,學習的課程和"01"號同學完全相同,那麼這個同學符合什麼條件呢?

第二步::概括上述的條件:對於x,他選修的所有課程,  肯定"不存在一門課程是不在01同學的課程內的"

概括出了第二步的條件,我很自然地寫出了下面錯誤的SQL:

SELECT x.*
FROM Student x
WHERE x.Sno != '01' AND NOT EXISTS
                (
                     SELECT*
                     FROM SC y
                     WHERE y.Sno = x.Sno AND NOT EXISTS
                          (
                              SELECT*
                              FROM SC z
                              WHERE z.Sno ='01' AND z.Cno = y.Cno));

為什麼會錯了,,我畫個圖就明白了:

 

大家懂了吧!!上面的SQL程式碼查詢出來的同學, 他們選修課程是01同學選修課程的子集,如圖所示,a同學和b同學也會被篩選出來,但是他們明顯不符合我們的結果  ......題目要求的是完全相同, 也就是要求等集,那麼我們該怎麼改進呢?

把第二步條件改為:  對於x,他選修的所有課程,  肯定"不存在一門課程是不在01同學的課程內的  && x選修的課程數等於01所選修的課程數"

正確SQL程式碼(非EXISTS查詢):

分析:

第一步:拿兩張SC表, 分別為x,y. 然後按照 x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno進行連線.  找出選修(01選修的課程) 

的記錄, 由於這邊還要輸出學生的姓名,所以我們拿張Student表繼續連線,以便輸出姓名等資訊

第二步:對第一步得到的表按照( Student.Sname,Student.Sno )進行分組, 然後用聚集函式判斷該學生選修的(01選修的課程) 數是否和01同學相同

SQL程式碼:

SELECT Student.Sname,Student.Sno
FROM  SC x,SC y,Student
WHERE Student.Sno =x.Sno AND x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno 
GROUP BY Student.Sname,Student.Sno
HAVING COUNT(y.Cno) =(
                        SELECT COUNT(*)
                        FROM SC
                        WHERE  SC.Sno ='01'); 

 

 

 

  • 型別九.按某種屬性排名,要求重複時 保留名次空缺

 什麼是保留名次空缺:

姓名   成績   排名
小A     99     1
小B     99     1
小C     98     3


/*
這裡小C的98分雖然是第2高分,但是它是年級第三名.因為第一名並列2個,因此第2的名次就空缺了
像這種排列方法,就稱為保留名次空缺.

每個人的名次 = 比我考得高分的人的數量 + 1
*/

​​​​​​​題目:按各科成績進行排序,並顯示排名, Score 重複時保留名次空缺

分析:

第一步: 拿兩張SC表,一張為x, 一張為y, 然後按照x.Cno = y.Cno AND y.Grade > x.Grade進行連線,目的是派生出一張表:

該表可以顯示看對於某學生的某個科目,有多少人考得比它高. 當然了,還要按照( x.Sno,x.Cno,x.Grade)進行分組,

COUNT( y.Grade) + 1就是名次了 (沒有加DISTINCE是預設不會去重的),該表稱為xx

 

第二步:拿Student表和xx表進行連線,以便輸出姓名等資訊

SQL程式碼:

​
SELECT Student.*,xx.Cno,xx.Grade,xx.名次
FROM (
      SELECT x.Sno,x.Cno,x.Grade, COUNT(y.Grade) + 1 AS 名次
      FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade > x.Grade)
      GROUP BY x.Sno,x.Cno,x.Grade
     ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

​

 

 

 

  • 型別10.按某種屬性排名,要求重複時 不保留名次空缺

什麼是不保留名次空缺:

姓名   成績   排名
小A     99     1
小B     99     1
小C     98     2


/*
這裡小C的98分是第2高分,,因此第2的名次就沒有空缺了
像這種排列方法,就稱為不保留名次空缺.

每個人的名次 = (>=我的分數型別有幾種 )
*/

 

題目:按各科成績進行排序,並顯示排名, Score 重複時合併名次(不保留名次空缺)

分析:

第一步: 拿兩張SC表,一張為x, 一張為y, 然後按照x.Cno = y.Cno AND y.Grade > x.Grade進行連線,目的是派生出一張表:

該表可以顯示看對於出某學生的某個科目,有多少人考得比它高. 當然了,還要按照( x.Sno,x.Cno,x.Grade)進行分組, COUNT(DISTINCT y.Grade) 就是 >=我的分數型別的種類數,也就是名次,  把這張表命名為xx

第二步:拿Student表和xx表進行連線,以便輸出姓名等資訊

SQL程式碼:

 

SELECT xx.*,xx.Cno, xx.名次
FROM ( SELECT x.Sno,x.Cno, COUNT(DISTINCT y.Grade) AS 名次
        FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >= x.Grade)
        GROUP BY x.Sno,x.Cno
       ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

 

 

 

 

  • 型別11:輸出優秀率或者及格率的題目


題目:以如下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率
及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90 (且要求輸出課程號和選修人數,查詢結果按選修人數降序排列,若人數相同,按課程號升序排列)  括號部分是我把另外一題合併進來的,更綜合

分析:

第一步:首先生成4張派生表:a,b,c,d.   a表用來統計各科優秀的人數    b表用來統計各科優良的人數  c表用來統計各科中等的人數

d表用來統計各科及格的人數

/*d表*/
SELECT Course.Cno, COUNT(Grade) AS 及格人數
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND SC.Grade >=60)
GROUP BY Course.Cno;

/*c表*/
SELECT Course.Cno, COUNT(Grade) AS 中等人數
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=70 AND Grade <80)
GROUP BY Course.Cno;
      
/*b表*/
SELECT Course.Cno, COUNT(Grade) AS 優良人數
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
GROUP BY Course.Cno ;

/*a表*/
SELECT Course.Cno, COUNT(Grade) AS 優秀人數
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno AND Grade >=90)
GROUP BY Course.Cno ;

第二步:生成派生表x,該表記錄了各科的最高分,最低分,平均分,選修總人數

/*派生表*/

SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 選修人數, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
FROM Course LEFT OUTER JOIN SC ON (Course.Cno = SC.Cno )
GROUP BY Course.Cno;

第三步. a,b,c,d,x這5張表進行連線,並且對結果進行排序

SQL程式碼:

SELECT x.Cno AS 課程ID ,Course.Cname AS 課程name,  x.選修人數,x.最高分,x.最低分 ,x.平均分 ,d.及格人數*1.0/x.選修人數 AS 及格率 ,c.中等人數*1.0/x.選修人數 AS  中等率,
        b.優良人數*1.0/x.選修人數 AS 優良率, a.優秀人數*1.0/x.選修人數 AS 優秀率          
FROM 

     (SELECT Course.Cno, COUNT(Grade) AS 及格人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=60)
      GROUP BY Course.Cno ) AS d ,
     
 
     (SELECT Course.Cno, COUNT(Grade) AS 中等人數
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade>=70 AND Grade <80)
      GROUP BY Course.Cno ) AS c ,
      

     (SELECT Course.Cno, COUNT(Grade) AS 優良人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
      GROUP BY Course.Cno ) AS b,

     (SELECT Course.Cno, COUNT(Grade) AS 優秀人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=90)
      GROUP BY Course.Cno ) AS a ,
  
     (SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 選修人數, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno )
      GROUP BY Course.Cno) AS x ,Course

WHERE d.Cno = c.Cno AND c.Cno = b.Cno AND b.Cno = a.Cno AND a.Cno = x.Cno AND x.Cno = Course.Cno
ORDER BY 選修人數 DESC, 課程ID ASC;

 

 

  • 型別十二: 查詢各科前幾名的記錄

題目:查詢各科成績前三名的記錄

分析:  這種查排名的題目,第一反應是要不要保留名次空缺,這題沒有提到,說明題目不嚴謹

保留名次空缺:核心思想跟型別9一樣

第一步:拿出兩張SC表,分別為x,y表, 用x表去左外連線y表, 這邊要用外連線,! 不然第一名的人由於沒有人分數比他高, 無法被篩選,

連線後, 對於某個人的某個科目,都能直接看出有多少人比他高

第二步:對第一步的表按(Student.Sname,Student.Sno,x.Cno)進行分組. 再用HAVING語句篩選 COUNT(y.Grade) < 3的分組

SQL程式碼:

SELECT Student.Sname,Student.Sno,x.Cno,COUNT(y.Grade) + 1 AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Sno = Student.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(y.Grade) < 3
ORDER BY x.Cno DESC, 名次 ASC;

 

 不保留名次空缺:核心思想跟型別10一樣

分析: 主要是一些條件變化了,直接看SQL程式碼比較差異,差異的原因請看型別10

SQL程式碼:

SELECT Student.Sname,Student.Sno,x.Cno,COUNT(DISTINCT y.Grade) AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Cno = y.Cno AND y.Grade >= x.Grade AND Student.Sno = x.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(DISTINCT y.Grade) <= 3
ORDER BY x.Cno DESC, 名次 ASC;

 

 

  • 型別13.  WHERE,GROUP BY ,HAVING ,ORDER BY的混合使用

題目:查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績,結果按平均成績進行降序排列

分析:

第一步:執行WHERE語句,把Student和SC表進行連線,形成一張表,暫且稱為x

第二步:按照( Student.Sno,Sname)對x表進行分組

第三步:執行HAVING語句,對每個分組進行篩選,篩選出AVG(SC.Grade) >=60的分組, 形成一張表,暫且稱為y表

第四步:執行SELECT語句,篩選出欄位,稱為z表

第五步:執行ORDER BY語句, 對z表進行排序,按照成績進行降序排序,稱為結果表

SQL程式碼:

SELECT Student.Sno,Sname,AVG(SC.Grade) AS 平均成績
FROM Student,SC
WHERE Student.Sno = SC.Sno
GROUP BY Student.Sno,Sname
HAVING AVG(SC.Grade) >=60
ORDER BY 平均成績 DESC;


 

 

  • 型別14.查詢任意成績都大於某個值的資訊

題目:查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數

分析:

第一步:拿出一張SC表 ,篩選出成績>=70的選課記錄

第二步:對第一步的表按x.Sno進行分組, 再用聚集函式篩選出 (>=70分的課程數) = (該學生選修的課程數)的分組.  稱為xx表

第三步:用xx表和Student,SC表進行連線,以便輸出姓名,課程名稱

SQL程式碼:

SELECT Student.Sname, xx.Sno,Course.Cname,z.Grade
FROM	(
         SELECT x.Sno
	 FROM   SC x
	 WHERE  x.Grade >=70
	 GROUP BY x.Sno
	 HAVING COUNT(x.Grade) = (
                           	SELECT COUNT(*)
                           	FROM SC y
                           	WHERE y.Sno = x.Sno )
         ) AS xx, Course,Student,SC z
WHERE xx.Sno = Student.Sno AND z.Sno = xx.Sno AND Course.Cno = z.Cno;

 

 

  • 型別15.查詢選修某老師所授課程的學生中,成績最高的學生資訊及其成績

題目:成績有重複的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生資訊及其成績

題目:成績不重複,查詢選修「張三」老師所授課程的學生中,成績最高的學生資訊及其成績

分析:這道題,由於是隻求最高分,  我的解法適用於成績有重複和不重複的兩種情況.

第一步:拿Course, Teacher,SC表進行連線,

第二步:由於1個老師可能教授多門課程,且有可能叫"張三"的老師又多個, 所以我們要按照(Teacher.Tno,SC.Cno)進行分組,並且篩選

 出對應的欄位,  其中一個欄位就是某個課程的最高分 ,稱為x表

第三步,再拿出一張SC表 ,Student表, 和x表進行連線 ,連線條件是:SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno,形成結果表

SQL程式碼:

SELECT  Student.*,SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='張三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;

​​​​​​​

 

  • 型別16.日期型別

分析:不同的關係型資料庫,日期型別和對應的函式都不 盡相同, 可以去官方查詢對應的文件,這邊忽略了

 

五.SQL程式碼大全(不包括日期的題目)

//1.查詢" 01 "課程比" 02 "課程成績高的學生的資訊及課程分數

SELECT Student.*,x.Grade AS 課程1,y.Grade AS 課程2
FROM SC x,SC y,Student
WHERE Student.Sno = x.Sno AND x.Sno = y.Sno AND x.Cno ='01' AND y.Cno ='02' AND x.Grade > y.Grade;


//2.查詢同時存在" 01 "課程和" 02 "課程的情況
SELECT DISTINCT x.Sno
FROM  SC x, SC y
WHERE x.Sno = y.Sno AND x.Cno ='01' AND y.Cno ='02';


//3.查詢存在" 01 "課程但可能不存在" 02 "課程的情況(不存在時顯示為 null )
SELECT x.*,y.Cno,y.Grade
FROM   (SELECT *
         FROM SC x
         WHERE Cno ='01'
         )  AS x

         LEFT OUTER JOIN 
         ( SELECT *
           FROM SC 
           WHERE Cno ='02'
         ) AS y ON (x.Sno = y.Sno);


 
//4.查詢不存在" 01 "課程但存在" 02 "課程的情況
SELECT  x.Sno
FROM SC x
WHERE x.Cno ='02' AND x.Sno  NOT IN(

  SELECT DISTINCT y.Sno
   FROM SC yx
   WHERE y.Cno ='01'


);


//5.查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績,結果按平均成績進行降序排列
SELECT Student.Sno,Sname,AVG(SC.Grade) AS 平均成績
FROM Student,SC
WHERE Student.Sno = SC.Sno
GROUP BY Student.Sno,Sname
HAVING AVG(SC.Grade) >=60
ORDER BY 平均成績 DESC;


//6.查詢在 SC 表存在成績的學生資訊
SELECT Student.*
FROM Student
WHERE Student.Sno IN (

  SELECT SC.Sno
  FROM SC 
  GROUP BY SC.Sno
);



//7.查詢所有同學的學生編號、學生姓名、選課總數、所有課程的總成績(沒成績的顯示為 null )
SELECT Student.Sno,Student.Sname,x.COUNT,x.SUM
FROM Student LEFT OUTER JOIN (
                              SELECT SC.Sno ,COUNT(SC.Cno),SUM(SC.Grade)
               		      FROM SC
              		      GROUP BY SC.Sno) AS x ON (Student.Sno = x.Sno);

// 8.查詢「李」姓老師的數量
SELECT COUNT(*)
FROM Teacher
WHERE Tname Like '李%';


//9.查詢學過「張三」老師授課的同學的資訊
SELECT ALL Student.*
FROM Course,Teacher,SC,Student
WHERE SC.Cno = Course.Cno AND SC.Sno = Student.Sno AND Course.Tno = Teacher.Tno AND Teacher.Tname 
      ='張三';

                                          
//10.查詢沒有學全所有課程的同學的資訊
SELECT *
FROM Student
WHERE EXISTS
      (
         SELECT*
         FROM Course
         WHERE NOT EXISTS
               (
                  SELECT*
                  FROM SC
                  WHERE SC.Sno= Student.Sno AND Course.Cno = SC.Cno ));


                     
//11.查詢至少有一門課與學號為" 01 "的同學所學相同的同學的資訊
SELECT DISTINCT Sno
FROM SC x
WHERE  EXISTS
      (
          SELECT*
          FROM SC y
          WHERE y.Sno = x.Sno AND  EXISTS
                (
                   
                    SELECT *
                    FROM SC z
                    WHERE z.Sno ='01' AND z.Cno = y.Cno));

 
  
//12.查詢和" 01 "號的同學學習的課程 完全相同的其他同學的資訊

SELECT Student.Sname,Student.Sno
FROM  SC x,SC y,Student
WHERE Student.Sno =x.Sno AND x.Sno !='01' AND y.Sno = '01' AND x.Cno = y.Cno 
GROUP BY Student.Sname,Student.Sno
HAVING COUNT(y.Cno) =(
                        SELECT COUNT(*)
                        FROM SC
                        WHERE  SC.Sno ='01'); 


//13.查詢沒學過"張三"老師講授的任一門課程的學生姓名
SELECT Sname    
FROM Student x   
WHERE NOT EXISTS
      (
        SELECT*
        FROM SC y
        WHERE  y.Sno = x.Sno AND  EXISTS
              (
                  SELECT*
                  FROM Teacher,Course
                  WHERE Teacher.Tno = Course.Tno AND y.Cno = Course.Cno  AND Teacher.Tname ='張三' ));




//14.查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績
SELECT Student.*,     (SELECT AVG(Grade)
                       FROM SC
                       WHERE SC.Sno = Student.Sno) AS 平均成績
FROM Student
WHERE Sno IN (
                SELECT Sno
	        FROM  SC 
                WHERE Grade < 60
	        GROUP BY Sno
                HAVING COUNT(Grade) >=2);
               
  


//15.檢索" 01 "課程分數小於 60,按分數降序排列的學生資訊
SELECT Student.*,Grade
FROM SC,Student
WHERE Student.Sno = SC.Sno AND  SC.Cno = '01' AND SC.Grade < 60
ORDER BY SC.Grade DESC;

//16.按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績
SELECT Student.Sno ,Sname,AVG(Grade) AS 平均成績
FROM SC,Student
WHERE SC.Sno = Student.Sno
GROUP BY Student.Sno ,Sname
ORDER BY 平均成績 DESC;

//17.查詢各科成績最高分、最低分和平均分:
SELECT Cno,MAX(Grade) AS 最高分,MIN(Grade) AS 最低分,AVG(Grade) AS 平均分
FROM SC 
GROUP BY Cno;


//18.以如下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率
及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90
要求輸出課程號和選修人數,查詢結果按選修人數降序排列,若人數相同,按課程號升序排列


SELECT x.Cno AS 課程ID ,Course.Cname AS 課程name,  x.選修人數,x.最高分,x.最低分 ,x.平均分 ,d.及格人數*1.0/x.選修人數 AS 及格率 ,c.中等人數*1.0/x.選修人數 AS  中等率,
        b.優良人數*1.0/x.選修人數 AS 優良率, a.優秀人數*1.0/x.選修人數 AS 優秀率          
FROM 

     (SELECT Course.Cno, COUNT(Grade) AS 及格人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=60)
      GROUP BY Course.Cno ) AS d ,
     
 
     (SELECT Course.Cno, COUNT(Grade) AS 中等人數
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade>=70 AND Grade <80)
      GROUP BY Course.Cno ) AS c ,
      

     (SELECT Course.Cno, COUNT(Grade) AS 優良人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=80 AND Grade <90)
      GROUP BY Course.Cno ) AS b,

     (SELECT Course.Cno, COUNT(Grade) AS 優秀人數
      FROM Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno AND Grade >=90)
      GROUP BY Course.Cno ) AS a ,
  
     (SELECT Course.Cno ,MAX(Grade) AS 最高分 ,COUNT(*) AS 選修人數, MIN(Grade) AS 最低分 ,AVG(Grade) AS 平均分
      FROM  Course LEFT OUTER JOIN SC ON  (Course.Cno = SC.Cno )
      GROUP BY Course.Cno) AS x ,Course

WHERE d.Cno = c.Cno AND c.Cno = b.Cno AND b.Cno = a.Cno AND a.Cno = x.Cno AND x.Cno = Course.Cno
ORDER BY 選修人數 DESC, 課程ID ASC;



//19.按各科成績進行排序,並顯示排名, Score 重複時保留名次空缺
SELECT Student.*,xx.Cno,xx.Grade,xx.名次
FROM (
      SELECT x.Sno,x.Cno,x.Grade, COUNT(y.Grade) + 1 AS 名次
      FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade > x.Grade)
      GROUP BY x.Sno,x.Cno,x.Grade
     ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;


//20.按各科成績進行排序,並顯示排名, Score 重複時合併名次
SELECT xx.*,xx.Cno, xx.名次
FROM ( SELECT x.Sno,x.Cno, COUNT(DISTINCT y.Grade) AS 名次
        FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >= x.Grade)
        GROUP BY x.Sno,x.Cno
       ) AS xx,Student
WHERE Student.Sno = xx.Sno
ORDER BY xx.Cno, xx.名次;

  
//21.查詢學生的總成績,並進行排名,總分重複時保留名次空缺   
SELECT  x.Sno,x.總分,COUNT( y.總分) + 1 AS 名次
FROM
        ( SELECT Sno,SUM(Grade) AS 總分
          FROM  SC 
	  GROUP BY Sno
         ) AS x 
         
         LEFT OUTER JOIN 

	( SELECT Sno,SUM(Grade) AS 總分
          FROM SC
	  GROUP BY Sno
        ) AS y  ON(y.總分 > x.總分)      

GROUP BY x.Sno,x.總分
ORDER BY x.總分 DESC;

//22.查詢學生的總成績,並進行排名,總分重複時不保留名次空缺
SELECT  x.Sno,Sname,x.總分,COUNT(DISTINCT y.總分) AS 名次
FROM
        ( SELECT Student.Sno,Sname,SUM(Grade) AS 總分
          FROM  Student LEFT OUTER JOIN SC ON(Student.Sno = SC.Sno )
	  GROUP BY Student.Sno,Sname
         ) AS x 
         
         LEFT OUTER JOIN 

	( SELECT Sno,SUM(Grade) AS 總分
          FROM SC
	  GROUP BY Sno
        ) AS y  ON(y.總分 >= x.總分)      

GROUP BY x.Sno,x.Sname,x.總分
ORDER BY x.總分 DESC;


//23.統計各科成績各分數段人數:課程編號,課程名稱,[100-85],[85-70],[70-60],[60-0] 及所佔百分比

SELECT x.Cno AS 課程編號,x.Cname AS 課程名稱,d.D*1.0/x.總人數 AS D比例, c.C*1.0/x.總人數 AS C比例,b.B*1.0/x.總人數 AS B比例, a.A*1.0/x.總人數 AS A比例
FROM 
     ( SELECT Course.Cno ,COUNT(SC.Grade) AS D
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=0 AND SC.Grade <60)
       GROUP BY Course.Cno
     ) AS d,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS C
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=60 AND SC.Grade <70)覆蓋 
       GROUP BY Course.Cno
     ) AS c,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS B
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=70 AND SC.Grade<85)
       GROUP BY Course.Cno
     ) AS b,
     ( SELECT  Course.Cno ,COUNT(SC.Grade) AS A
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno AND SC.Grade >=85 AND SC.Grade < 100)
       GROUP BY Course.Cno
     ) AS a,
     ( SELECT Course.Cno ,Course.Cname,COUNT(SC.Grade) AS 總人數
       FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
       GROUP BY Course.Cno,Course.Cname
     ) AS x
WHERE a.Cno = b.Cno AND b.Cno = c.Cno AND c.Cno = d.Cno AND d.Cno = x.Cno;



//24.查詢每門課程被選修的學生數
SELECT Course.Cno,Course.Cname,COUNT(SC.Sno) AS 學生數
FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
GROUP BY Course.Cno,Course.Cname;

       
//25 .查詢各科成績前三名的記錄
保留名次空缺:
SELECT Student.Sname,Student.Sno,x.Cno,COUNT(y.Grade) + 1 AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Sno = Student.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(y.Grade) < 3
ORDER BY x.Cno DESC, 名次 ASC;


//不保留名次空缺
SELECT Student.Sname,Student.Sno,x.Cno,COUNT(DISTINCT y.Grade) AS 名次
FROM SC AS x LEFT OUTER JOIN SC AS y ON  (x.Cno = y.Cno AND y.Grade > x.Grade),Student
WHERE x.Cno = y.Cno AND y.Grade >= x.Grade AND Student.Sno = x.Sno
GROUP BY Student.Sname,Student.Sno,x.Cno
HAVING COUNT(DISTINCT y.Grade) <= 3
ORDER BY x.Cno DESC, 名次 ASC;



//26.查詢出只選修兩門課程的學生學號和姓名
SELECT Student.Sno,Sname
FROM Student LEFT OUTER JOIN SC ON (SC.Sno = Student.Sno) 
GROUP BY Student.Sno,Sname
HAVING COUNT(SC.Cno) =2;

//27.查詢男生、女生人數
SELECT Ssex,COUNT(*) AS 人數
FROM Student
GROUP BY Ssex;

//28.查詢名字中含有「風」字的學生資訊
SELECT *
FROM Student
WHERE Sname LIKE '%風%';


//29.查詢同名同性學生名單,並統計同名人數
SELECT x.Sname, COUNT(y.Sname) AS 人數
FROM Student x,Student y
WHERE x.Sname =y.Sname AND x.Ssex = y.Ssex AND x.Sno !=y.Sno
GROUP BY x.Sname;

//30.查詢 1990 年出生的學生名單
SELECT Student.*
FROM Student
WHERE extract(year from Sage) = 1990;

//31.查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編號升序排列
SELECT Cno,AVG(Grade) AS 平均成績
FROM SC
GROUP BY Cno
ORDER BY 平均成績 DESC, Cno ASC; 

//32.查詢平均成績大於等於 85 的所有學生的學號、姓名和平均成績
SELECT x.Sno,Student.Sname,AVG(y.Grade) AS 平均成績
FROM SC x, SC y,Student
WHERE x.Sno = y.Sno AND Student.Sno = y.Sno
GROUP BY x.Sno,Student.Sname
HAVING AVG(y.Grade) >= 85;

//33.查詢課程名稱為「數學」,且分數低於 60 的學生姓名和分數
SELECT Student.Sname,SC.Grade
FROM Student, SC,Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno AND Course.Cname ='數學'AND SC.Grade <60;

//34.查詢所有學生的課程及分數情況(存在學生沒成績,沒選課的情況)
SELECT Student.*,SC.Cno ,Course.Cname ,SC.Grade
FROM Student LEFT OUTER JOIN SC ON (Student.Sno = SC.Sno)  LEFT OUTER JOIN Course ON (Course.Cno = SC.Cno);


//35.查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數
SELECT Student.Sname, xx.Sno,Course.Cname,z.Grade
FROM	(
         SELECT x.Sno
	 FROM   SC x
	 WHERE  x.Grade >=70
	 GROUP BY x.Sno
	 HAVING COUNT(x.Grade) = (
                           	SELECT COUNT(*)
                           	FROM SC y
                           	WHERE y.Sno = x.Sno )
         ) AS xx, Course,Student,SC z
WHERE xx.Sno = Student.Sno AND z.Sno = xx.Sno AND Course.Cno = z.Cno;


//36.查詢不及格的課程
SELECT  Student.*,SC.Cno,Course.Cname,SC.Grade
FROM SC,Student,Course
WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno AND SC.Grade < 60;

//37.查詢課程編號為 01 且課程成績在 80 分以上的學生的學號和姓名
SELECT Student.Sno ,Student.Sname,SC.Cno,Course.Cname,SC.Grade
FROM SC ,Student,Course
WHERE SC.Sno = Student.Sno AND SC.Cno = Course.Cno AND SC.Cno = '01' AND SC.Grade >=80;



//38.求每門課程的學生人數
SELECT Course.Cno,Course.Cname,COUNT(*) AS 選修人數
FROM Course LEFT OUTER JOIN SC ON (SC.Cno = Course.Cno)
GROUP BY Course.Cno,Course.Cname;

//39.成績不重複,查詢選修「張三」老師所授課程的學生中,成績最高的學生資訊及其成績
SELECT  Student.*,SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='張三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;

          

//40.成績有重複的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生資訊及其成績
SELECT  Student.*,x.SC.Cno,SC.Grade
FROM    (
          SELECT Teacher.Tno,  SC.Cno,MAX(SC.Grade) AS MaxGrade
          FROM  Course ,Teacher,SC
	  WHERE Course.Tno = Teacher.Tno AND Course.Cno = SC.Cno  AND Teacher.Tname ='張三'
          GROUP BY Teacher.Tno,SC.Cno
         )AS x, SC,Student

WHERE SC.Grade = x.MaxGrade AND SC.Cno = x.Cno AND Student.sno = SC.Sno;


//41.查詢不同課程成績相同的學生的學生編號、課程編號、學生成績
SELECT x.Sno, x.Cno As Cno1 ,y.Cno As Con2,x.Grade AS 相同成績
FROM SC x ,SC y
WHERE x.Grade = y.Grade AND x.Sno = y.Sno AND x.Cno != y.Cno;


//42.查詢每門功成績最好的前兩名
       SELECT x.Sno,x.Cno,x.Grade ,COUNT(y.Grade) AS Cnt
       FROM SC AS x LEFT OUTER JOIN SC AS y ON (x.Cno = y.Cno AND y.Grade >x.Grade)
       GROUP BY x.Sno,x.Cno,x.Grade
       HAVING COUNT(y.Grade)  < 2;

//43.查詢選修了全部課程的學生資訊
SELECT *
FROM Student x
WHERE NOT EXISTS
      (
          SELECT*
          FROM Course y
          WHERE  NOT EXISTS
             (
                SELECT*
                FROM SC z
                WHERE z.Sno = x.Sno AND z.Cno = y.Cno ));