隨便玩玩之PostgreSQL(第二章)單表數據查詢
未經授權不得轉載
第二章 單表數據查詢
數據庫的基本功能就是數據增查改刪,倘若不可以,要她還有什么意義。數據查詢功能不僅僅是查詢,而且還能篩選,並且格式化顯示。
數據查詢使用SELECT語句,本章介紹如何使用SELECT查詢(列出)數據庫中的數據。
2.1查詢數據庫cj表中全部信息
方法一:使用“*”通配符查詢所有數據(所有字段數據)。
SELECT * FROM cj;
結果如圖。
方法二:制定所有字段(列名)。每個字段用逗號(,)隔開。
SELECT id,kc,bj,xm,yw,sx,yy FROM cj;
結果如圖。
2.2查詢數據庫中指定字段信息(只顯示出想要的列)。
只要是表內的字段就可以,重復也可以,字段數量最多1664個。
SELECT xm,yw FROM cj;
結果列出所有學生的姓名和語文成績。
2.4查詢指定記錄(只顯示想要的行)。
數據庫的信息本來就包含了各種信息,如cj表中包括一班、二班、三班的每一個學生的考試成績。倘若查詢一班所有人的成績,可以查出所有人的成績,然后在EXCEL中刪掉二班、三班的。數據量少的時候可以這樣,數據量多的時候速度就會下降。不過,我們可以通過限制查詢條件進行查詢,按條件查詢(列出)數據。
SELECT * FROM cj WHERE bj='一班';
結果如圖。
語句中的等號(=)表示只查詢bj字段為一班的學生的成績。等號為判斷符,其他判斷符為<>(或者!=,表示不等於),<(表示左邊數值小於右邊數值),<=(表示小於等於右邊數值),>(表示大於右邊數值),>=(表示大於等於右邊數值),BETWEEN AND(表示介於兩個數值之間)。
如:
1 --查詢語文成績大於60的學生。 2 SELECT * FROM cj WHERE yw > 60;
3 --查詢語文成績在60到69之間的學生。 4 SELECT id,bj,xm,yw FROM cj WHERE yw BETWEEN 60 AND 69; 5 --或者 6 SELECT id,bj,xm,yw FROM cj WHERE yw>=60 AND yw<69; --結果與第四行語句相同。
7 --查詢語文成績不是60到69的學生。 8 SELECT * FROM cj WHERE yw NOT BETWEEN 60 AND 69; 9 --或者 10 SELECT * FROM cj WHERE yw>69 OR yw <60;
11 --查詢英語成績等60的學生。 12 SELECT * FROM cj WHERE yy=60;
13 --查詢英語成績等於60且必須等於70的學生(無意義,沒結果且不合邏輯)。 14 SELECT * FROM cj WHERE yy=60 AND yy=70;
15 --查詢張三的成績。 16 SELECT * FROM cj WHERE xm=’張三’;
17 --查詢張三其中考試的成績。 18 SELECT * FROM cj WHERE xm='張三' AND kc='期中考試';
19 --查詢語文成績大於80和(或)小於65的學生。 20 SELECT * FROM cj WHERE yw > 80 OR yw<65;
2.4多條件查詢
多條件查詢使用AND或OR操作符,可以指定2個及以上的條件。
AND操作符限定滿足所有條件才會有記錄返回。
如:查詢期中考試三班語文成績大於80的學生。
SELECT * FROM cj WHERE kc='期中考試' AND bj='三班' AND yw>80;
OR操作符只需所有條件中滿足一個條件即可。
如:查詢語文成績大於80或一班的學生。
SELECT * FROM cj WHERE yw>80 OR bj='一班';
用IN操作符實現OR操作符功能。
如:查詢英語成績等於60和(或)70的學生。
--OR操作符 SELECT * FROM cj WHERE yy=60 OR yy=70; --IN操作符 SELECT * FROM cj WHERE yy in (60,70);
2.5 去掉查詢結果中的重復記錄。
cj表中共有18個學生的信息,每一個信息都有一個班級。想要從表中得到有多少個班級,只有查詢出所有班級字段,然后去掉重復的,只保留一個,即可得到班級數量。使用DISTINCT關鍵字即可去掉重復記錄,只保留一個記錄值。
SELECT DISTINCT bj FROM cj;
結果如圖。
結果把所有的班級只列出一個,只需要數一數有多少行即可得出有三個班級。
也有不想數行的方法,使用count()函數即可實現。
SELECT count(DISTINCT bj) FROM cj;
結果如圖。
2.6對查詢結果排序
默認查詢結果沒有排序,有可能每次的查詢結果順序都不一樣。使用ORDER BY子句可以對結果進行排序。
如:從低到高列出所有學生的語文成績。
SELECT xm,yw,bj,kc FROM cj ORDER BY yw;
結果如圖。
如:先分期中考試、期末考試,在從低到高列出所有學生語文成績。
SELECT kc,yw,bj,xm FROM cj ORDER BY kc,yw;
結果如圖。
默認排序為1-9,A-Z,逆序排列只需要在字段后加DESC關鍵字即可,DESC約束其前的字段,如果對所有排序條件逆序,需在所有關鍵字后加DESC。
如:列出從高到低列出所有學生期中考試語文成績。
SELECT kc,yw,bj,xm FROM cj WHERE kc='期中考試' ORDER BY kc,yw DESC;
結果如圖。
2.7查詢結果分組
分組排序使用GROUP BY子句。
但是分組之后組字段顯示的值是什么?做班級成績匯報時,一般說一班有多少個人,語文平均分是多少,語文最高分是多少,最低分是多少,不會說出每個人的成績,也不會隨便說一個人的成績。所以分組之后顯示的是計算的結果,計算使用聚合函數。常用的聚合函數有:計數量count(),求最大值max(),求最小值min(),計總和sum(),求平均avg()。
如:計算出各班的期中考試平均。
SELECT bj,avg(yw),avg(sx),avg(yy) FROM cj WHERE kc='期中考試' GROUP BY bj;
結果如圖。
小數點太多?可以用round()函數截取。
SELECT bj,round(avg(yw),2),avg(sx),avg(yy) FROM cj WHERE kc='期中考試' GROUP BY bj;
結果如圖。
一行的SQL語句太長?可以分行寫SQL語句,只要在最后有一個分號就可以。
SELECT bj, round(avg(yw),2), avg(sx),avg(yy) FROM cj WHERE kc='期中考試' GROUP BY bj;
結果如圖。
語句換行不影響查詢結果。
表頭都是AVG,不美觀?使用AS關鍵字設置別名即可。
SELECT bj AS "班級", round(avg(yw),2) AS "語文平均分", avg(sx) AS "數學平均分", avg(yy) AS "英語平均分" FROM cj WHERE kc='期中考試' GROUP BY bj;
結果如圖。
AS的功能是給字段起一個別名。
數據沒有排序,看起來不方便?分組之后再排序。
SELECT bj AS "班級", round(avg(yw),2) AS "語文平均分", avg(sx) AS "數學平均分", avg(yy) AS "英語平均分" FROM cj WHERE kc='期中考試' GROUP BY bj ORDER BY avg(yw);
結果如圖。
注:最后的ORDER BY指定的不是字段本身,而是使用聚合函數計算后的字段。已經給avg(yw)設置了別名,那么ORDER BY 能使用別名作為排序條件嗎?當然可以。
SELECT bj AS "班級", round(avg(yw),2) AS "語文平均分", avg(sx) AS "數學平均分", avg(yy) AS "英語平均分" FROM cj WHERE kc='期中考試' GROUP BY bj ORDER BY "語文平均分";
結果如圖。
2.8查詢結果分組排序后再篩選
使用WHERE關鍵字可以篩選過濾數據,但是WHERE的篩選只能是指定選擇記錄的條件,請記住:WHERE關鍵字是用在記錄上的。對於分組之后的組有該如何篩選?HAVING關鍵字用來篩選分組之后的數據。
如:篩選出期中考試語文平均分大於70的班級。
SELECT bj AS "班級", round(avg(yw),2) AS "語文平均分", avg(sx) AS "數學平均分", avg(yy) AS "英語平均分" FROM cj WHERE kc='期中考試' GROUP BY bj HAVING avg(yw)>70;
結果如圖。
2.9限制查詢結果數量。
SELECT將返回所有匹配的行,可能是表中的所有行,如僅僅需要返回第一行或前幾行,使用LIMIT關鍵字。
如:查詢cj前3行的數據。
SELECT * FROM cj LIMIT 3;
結果如圖。
也可以查詢從第4行開始的3條記錄。
SELECT * FROM cj LIMIT 3 OFFSET 4;
結果如圖。
數據庫本身的記錄(行)從0開始計算,第4行應理解為數據庫的第5個記錄。
2.10 階段性總結示例:使用聚合函數實現分類匯總
count()函數計算表內行的總數。方法有兩種:count(*)計算表內行的總數,包括空值。Count(字段名)計算指定列行的總數,忽略空值。
sum()函數計算一個列的所有記錄累計總和。
avg()函數計算一個列的所有記錄的平均值。
Max()函數返回一個列的所有記錄中的最大值。
Min()函數返回一個列的所有記錄中的最小值。
如:分類匯總功能。
1 SELECT bj AS "班級" , 2 count(xm) AS "人數" , 3 round(sum(yw)/count(xm),2) AS "語文" , 4 -- round(avg(yw),2) AS "語文" , 5 max(yw) AS "語文最高分" , 6 min(yw) AS "語文最低分" , 7 round(avg(sx),2) AS "數學平均分" , 8 max(sx) AS "數學最高分" , 9 min(sx) AS "數學最低分" , 10 round(avg(yy),2) AS "英語平均分" , 11 max(yy) AS "英語最高分" , 12 min(yy) AS "英語最低分" 13 FROM cj 14 WHERE kc = '期中考試' 15 GROUP BY bj 16 ORDER BY avg(yw);
結果如圖。
使用方法非常靈活,一條語句搞定。
2.11子查詢
子查詢是把一個查詢嵌套在另一個查詢中。子查詢又叫內部查詢,相對於內部查詢,包含着子查詢的叫外部查詢。
子查詢可以包含普通select可以包括的任何子句,比如:distinct、 group by、order by、limit、join和union等;但是對應的外部查詢必須是以下語句之一:select、insert、update、delete、set或 者do。
子查詢可以在SELECT后,FROM后,WHERE后,GROUP BY后和ORDER BY后。
根據返回值類型,子查詢分為標量子查詢(單一值子查詢,返回一個值)、列子查詢(返回一列值)、行子查詢(返回一行值)、表子查詢(返回一個表的值),
可以使用的操作符:= > < >= <= <> ANY IN SOME ALL EXISTS 。
2.11.1標量子查詢
標量子查詢返回一個值,可以與外部查詢使用=、>、<、>=、<=和<>符號進行比較判斷,如果子查詢返回的不是一個標量值,而外部查詢使用了比較符和子查詢的結果進行了比較,那么就會拋出異常。
如:查詢期中考試語文成績高於張三的學生。
1 SELECT * 2 FROM cj 3 WHERE yw > 4 (SELECT yw FROM cj WHERE kc='期中考試' AND xm ='張三') 5 AND kc='期中考試';
結果如圖:
得到的結果是把期中考試語文成績高於張三的學生全部列出來,最后的AND kc='期中考試'判斷條件是將結果限定在期中考試內,去掉這一句會列出期中考試和期末考試成績。
其執行循序為:先執行(SELECT yw FROM cj WHERE kc='期中考試' AND xm = '張三'),得到張三的期中考試語文成績,為64,再和yw>組成判斷表達式yw>64;yw>64和AND kc='期中考試'組成邏輯與表達式(兩個結果都為真),最后執行外部語句(整個語句)。
關於子查詢請記住,語句里有括號,則先執行括號內部查詢(子查詢),得到結果,作為外部查詢的一部分,再執行部查詢。
也可以把子查詢放在SELECT后。
如:查詢張三的期中考試和期末考試語文成績,以及兩者之間的差距。
SELECT xm AS "姓名" , yw AS "期中考試" , (SELECT yw FROM cj WHERE kc='期末考試' AND xm='張三') AS "期末考試" , yw - (SELECT yw FROM cj WHERE kc='期末考試' AND xm='張三') AS "差距" FROM cj WHERE kc='期中考試' AND xm='張三';
結果如下:
如上所釋,先執行括號內語句(子查詢),結果作為外部語句(整個語句)組成部分,再執行外部語句。
2.11.2列子查詢
列子查詢返回一個列的數據,可以使用 = > < >= <= <> 這些操作符對子查詢的結果進行比較,通常子查詢的位置在比較式的右側。可以使用 IN、ANY、SOME 和 ALL 操作符,不能直接使用 = > < >= <= <> 這些比較標量結果的操作符。
ALL操作符是所有、全部的意思。只有全部符合條件,外部語句才有結果。例如,>(1,2,3)表示必須大於3。(注:NOT IN 與<>ALL等效)
如:查詢語文成績比數學最高分還高的同學。
SELECT xm AS "姓名" , yw AS "語文成績" , (SELECT max(sx) FROM cj) AS "全部學生數學最高分" FROM cj WHERE yw > ALL (SELECT sx FROM cj); --左邊大於右邊最大的
結果如圖。
ANY操作符是任意一個的意思。滿足任何一個即可。例如:>ANY(1,2,3)表示大於1即可。
SOME操作符與ANY相同。
如:查詢數學成績比語文最低分高的學生。
SELECT xm AS "姓名", sx AS "數學", (SELECT min(yw) FROM cj) AS "語文最低分" FROM cj WHERE sx > ANY (SELECT yw FROM cj) ORDER BY sx DESC;
結果如圖。
當判斷對象中一個是另一個的子集時,ANY與IN等效,結果一樣。
2.11.3行子查詢
如:查詢表內信息是否在另一個表中完全一致。
SELECT * FROM (SELECT * FROM cj WHERE id = 5) id5 --FROM后的子查詢得到一行數據 WHERE (id,kc,bj,xm,yw,sx,yy) IN (SELECT * FROM cj);
結果如圖。
2.11.4表子查詢
結果得到一個表。
如:查詢所有學生的期中考試成績。
1 SELECT * 2 FROM (SELECT * FROM cj WHERE kc='期中考試') kc_qz; 3 -- 和 SELECT * FROM cj WHERE kc='期中考試'; 語句的執行結果相同,不同的是查詢的表不一樣。
結果如下。
代碼內有注釋。結果相同,查詢的表不相同。行3的語句是直接從cj表內查詢;行2的語句是執行一個查詢,得到的結果為表。
注:給表起別名只需在表后加空格和名稱。
2.11.5 階段性總結示例:利用子查詢求班級平均分差距。
1 SELECT kc_qz.bj AS "期中班級" , 2 kc_qm.bj AS "期末班級" , 3 -- 增加班級一列(kc_qm.bj),用來識別班級,無特殊意義 4 round(kc_qz.yw1,2) AS "期中語文" , 5 round(kc_qm.yw2,2) AS "期末語文" , 6 round(kc_qm.yw2-kc_qz.yw1,2) AS "語文差距" , 7 -- 分數差距,正數表示期末考試相對期中考試有提升,負數表示下降 8 round(kc_qz.sx1,2) AS "期中數學" , 9 round(kc_qm.sx2,2) AS "期末數學" , 10 round(kc_qm.sx2 - kc_qz.sx1,2) AS "數學差距" , 11 round(kc_qz.yy1,2) AS "期中英語" , 12 round(kc_qm.yy2,2) AS "期末英語" , 13 round(kc_qm.yy2 - kc_qz.yy1,2) AS "英語差距" 14 FROM 15 (SELECT bj, 16 avg(yw) AS "yw1", 17 avg(sx) AS "sx1", 18 avg(yy) AS "yy1" 19 FROM cj 20 WHERE kc='期中考試' 21 GROUP BY bj) kc_qz, 22 (SELECT bj, 23 avg(yw) AS "yw2", 24 avg(sx) AS "sx2", 25 avg(yy) AS "yy2" 26 FROM cj 27 WHERE kc='期末考試' 28 GROUP BY bj) kc_qm 29 WHERE kc_qz.bj = kc_qm.bj -- 表連接查詢,下一章內容 30 ORDER BY kc_qz.bj;
結果如圖。
看起來是30行,實際上只是一條語句。
至此,第二章結束,簡單介紹了單表查詢,語句都很簡單,但是很神奇。