我們在上一節介紹了如何使用 ASP 來讀取資料庫中的資料,並將其呈現於網頁中。ASP 與資料庫溝通的標準語言就是 SQL,經由此種語言,我們才能在 ASP 程式碼對資料庫進行檢視、新增、修改、刪除等動作。本節將對 SQL 進一步介紹其用法。
SQL 是「結構化查詢語言」(Structured Query Language)的簡稱,是由 IBM 公司於 1970 年代所發展出來,用於關聯式資料庫 (Relational Databases) 當中的一種資料庫查詢語言,利用 SQL 可以用來進行各種與資料庫相關的處理,例如:
- 產生資料庫內的資料表
- 定義資料表內的欄位與相關資料型態
- 建立表格之間的關聯性
- 對資料進行處理:新增、修改、刪除、查詢
- 對資料進行統計
由於 SQL 功能定義完整,所以已經成為一個查詢資料庫的標準語言。雖然各家資料庫所提供的 SQL 語言在功能上會略有差異,但基本的功能是一致的。本單元將 ASP 與資料庫整合最常用到的SQL語法做一個整理,由於 SQL 的語法相當平易近人,所以讀者只要對以下的語法稍做了解之後,即可馬上進入 ASP 與資料庫整合的世界。
任何資料庫都有四個基本查詢動作,即檢視、新增、修改、刪除,以下將逐一介紹這四種基本功能的 SQL 語法,以及相關的範例。
若要檢視資料庫的資料,使用的 SQL 主要指令是「SELECT」,基本語法如下:
SELECT 欄位名稱1, 欄位名稱2, ...
FROM 資料表名稱1, 資料表名稱2, ...
[WHERE 條件式]
[ORDER BY 欄位名稱1, 欄位名稱2, ...]
說明如下:
- SELECT 其後所接的欄位名稱為待查資料庫的欄位名稱。
- FROM 其後所接的資料表名稱為待查資料庫的資料表名稱。
- WHERE 其後所接的條件式為設定查詢的條件式。(加上中括弧,表示這是選擇性的敘述。)
- ORDER BY 其後所接的欄位名稱為欲排序的欄位,可將查詢的資料根據這些欄位來排序。指定多個欄位時,則以「欄位名稱1」排序,若其資料相同則再依「欄位名稱2」排序,依此類推。(加上中括弧,表示這是選擇性的敘述。)
SQL 的設計基本上是模仿英文的自然語法,因此在入門上較為容易。接著我們來看看幾個範例,就可以瞭解 SQL 的精髓。
首先,我們以資料庫 asr/example/database/basketball.mdb 為例,這個資料庫包含兩個資料表:
- Player 包含球員的資料,其中 TeamID 是球員所隸屬的籃球隊代號(載明在 Team 資料表),Percentage 是投籃的命中率。
- Team 包含籃球隊的資料,其中 WinNo 是本季的贏球次數。
相關內容如下:
資料庫 "example/database/basketball.mdb"
|
資料表 "Player" 的內容
| 資料表 "Team" 的內容
|
ID |
NickName |
Name |
TeamID |
Percentage |
---|
1 | jean | 吳志銘 | 1 | 38.25 | 2 | jones | 張秤嘉 | 5 | 49.77 | 3 | ben | 陳孜彬 | 1 | 50.26 | 4 | asser | 林惠娟 | 3 | 37.22 | 5 | window | 李宜揚 | 1 | 36.67 | 6 | roger | 張智星 | 2 | 25.88 | 7 | cosh | 許文豪 | 6 | 70.98 | 8 | banny | 洪鵬翔 | 6 | 88.97 | 9 | shyba | 邱中人 | 5 | 67.45 | 10 | batty | 楊璧如 | 4 | 65.55 | 11 | joey | 許嘉晉 | 3 | 47.65 | 12 | roland | 吳瑞千 | 1 | 55.87 | 13 | sony | 林頌華 | 1 | 54.77 | 14 | beball | 葉佳慧 | 5 | 33.33 | 15 | gavins | 林政源 | 5 | 55.65 | 16 | jojo | 陳俊傑 | 5 | 44.65 | 17 | jtchen | 陳江村 | 3 | 48.76 | 18 | Gao | 高名揚 | 1 | 67.88 | 19 | Wayne | 陳智偉 | 7 | 65.87 | 20 | chingz | 陳晴 | 5 | 57.28 |
| ID |
Name |
WinNo |
---|
1 | 台北隊 | 12 | 2 | 新竹隊 | 7 | 3 | 台中隊 | 10 | 4 | 南投隊 | 12 | 5 | 台南隊 | 17 | 6 | 高雄隊 | 16 | 7 | 澎湖隊 | 11 |
|
以下是幾個檢視指令的基本範例,都只有牽涉到單一資料表。(讀者可以只看 SQL 指令,猜猜它的意義,再看看中文解譯。)
-
SQL指令:SELECT * FROM Team
意義:所有球隊資料
說明:「*」代表 Team 資料表中所有的欄位。
查詢結果:ID |
Name |
WinNo |
---|
1 | 台北隊 | 12 |
2 | 新竹隊 | 7 |
3 | 台中隊 | 10 |
4 | 南投隊 | 12 |
5 | 台南隊 | 17 |
6 | 高雄隊 | 16 |
7 | 澎湖隊 | 11 |
-
SQL指令:SELECT TOP 3 * FROM Team
意義:所有球隊資料,但只抓前三筆
說明:「TOP 3」代表只抓取前三筆資料。也可以使用「TOP 25 percent」等,代表抓取所有資料的前百分之二十五。
查詢結果:ID |
Name |
WinNo |
---|
1 | 台北隊 | 12 |
2 | 新竹隊 | 7 |
3 | 台中隊 | 10 |
-
SQL指令:SELECT Name, Percentage FROM Player WHERE NickName='gavins'
意義:綽號為 gavins 的球員姓名及命中率
查詢結果:Name |
Percentage |
---|
林政源 | 55.65 |
-
SQL指令:SELECT * FROM Team WHERE Name like '台%'
意義:隊名以「台」開頭的球隊資料
說明:「%」代表任意長度的字串。
查詢結果:ID |
Name |
WinNo |
---|
1 | 台北隊 | 12 |
3 | 台中隊 | 10 |
5 | 台南隊 | 17 |
-
SQL指令:SELECT Name, Percentage FROM Player WHERE Name like '陳__'
意義:「姓陳且名字有三個字」的球員姓名及命中率
說明:「_」代表任意單一字元。
查詢結果:Name |
Percentage |
---|
陳孜彬 | 50.26 |
陳俊傑 | 44.65 |
陳江村 | 48.76 |
陳智偉 | 65.87 |
-
SQL指令:SELECT Name, WinNo FROM Team WHERE WinNo>10
意義:「勝場數大於10」的球隊名稱及其勝場數
查詢結果:Name |
WinNo |
---|
台北隊 | 12 |
南投隊 | 12 |
台南隊 | 17 |
高雄隊 | 16 |
澎湖隊 | 11 |
-
SQL指令:SELECT Name, WinNo FROM Team WHERE WinNo>10 ORDER BY WinNo DESC
意義:「勝場數大於10」的球隊名稱及其勝場數,並根據勝場數由大到小排列
說明:若不加入 DESC,則會進行由小到大的排序。
查詢結果:Name |
WinNo |
---|
台南隊 | 17 |
高雄隊 | 16 |
南投隊 | 12 |
台北隊 | 12 |
澎湖隊 | 11 |
-
SQL指令:SELECT TeamID, Name, Percentage FROM Player WHERE TeamID=5 ORDER BY Percentage DESC
意義:「球隊代碼為5」的球員命中率排行榜
查詢結果:TeamID |
Name |
Percentage |
---|
5 | 邱中人 | 67.45 |
5 | 陳晴 | 57.28 |
5 | 林政源 | 55.65 |
5 | 張秤嘉 | 49.77 |
5 | 陳俊傑 | 44.65 |
5 | 葉佳慧 | 33.33 |
-
SQL指令:SELECT * FROM Player ORDER BY TeamID, Percentage DESC
意義:每一隊的球員命中率排行榜
說明:列出結果會先按 TeamID 由小到大排序,再按 Percentage 由大到小排序。
查詢結果:ID |
NickName |
Name |
TeamID |
Percentage |
---|
18 | Gao | 高名揚 | 1 | 67.88 |
12 | roland | 吳瑞千 | 1 | 55.87 |
13 | sony | 林頌華 | 1 | 54.77 |
3 | ben | 陳孜彬 | 1 | 50.26 |
1 | jean | 吳志銘 | 1 | 38.25 |
5 | window | 李宜揚 | 1 | 36.67 |
6 | roger | 張智星 | 2 | 25.88 |
17 | jtchen | 陳江村 | 3 | 48.76 |
11 | joey | 許嘉晉 | 3 | 47.65 |
4 | asser | 林惠娟 | 3 | 37.22 |
10 | batty | 楊璧如 | 4 | 65.55 |
9 | shyba | 邱中人 | 5 | 67.45 |
20 | chingz | 陳晴 | 5 | 57.28 |
15 | gavins | 林政源 | 5 | 55.65 |
2 | jones | 張秤嘉 | 5 | 49.77 |
16 | jojo | 陳俊傑 | 5 | 44.65 |
14 | beball | 葉佳慧 | 5 | 33.33 |
8 | banny | 洪鵬翔 | 6 | 88.97 |
7 | cosh | 許文豪 | 6 | 70.98 |
19 | Wayne | 陳智偉 | 7 | 65.87 |
-
SQL指令:SELECT count(*) FROM Team WHERE WinNo>10
意義:「勝場數大於10」的球隊總數
說明:count()函數會計算資料筆數,資料庫會自動產生暫時的欄位名稱 Expr1000。
查詢結果:
-
SQL指令:SELECT max(Percentage) as 最高命中率 FROM Player
意義:所有球員的最高命中率
說明:max(Percentage)函數會計算命中率最大值。由於使用了「as 最高命中率」,資料庫會自動產生暫時的欄位名稱「最高命中率」。
查詢結果:
-
SQL指令:SELECT TOP 1 Name, Percentage FROM Player ORDER BY Percentage DESC
意義:具有最高命中率的球員資料
查詢結果:Name |
Percentage |
---|
洪鵬翔 | 88.97 |
-
SQL指令:SELECT Name, Percentage FROM Player WHERE Percentage in (SELECT max(Percentage) FROM Player)
意義:具有最高命中率的球員資料
說明:功能同前一個範例,但是改用兩個 SQL 指令組合來達成同樣的效果。
查詢結果:Name |
Percentage |
---|
洪鵬翔 | 88.97 |
在上述範例中,我們已經知道如何使用 count 或是 max 函數來進行統計,但若要根據欄位值不同來進行統計,就必須用到群組指令「GROUP BY」,若還要指定相關條件,就必須用到群組條件「HAVING」,因此 SQL 所使用的 SELECT 指令格式就會比較複雜,如下:
SELECT 欄位名稱1, 欄位名稱2, ...
FROM 資料表名稱1, 資料表名稱2, ...
[WHERE 條件式]
[GROUP BY 欄位名稱1, 欄位名稱2, ...]
[HAVING 條件式]
[ORDER BY 欄位名稱1, 欄位名稱2, ...]
我們針對新增的敘述來說明如下:
- GROUP BY 其後所接的欄位名稱為需要聚合的欄位名稱。(所謂「聚合」,就是將相同欄位值的數筆資料合成一筆新資料。)
- HAVING 其後所接的條件式,則會用在聚合後的資料篩選。
以下是幾個使用到 GROUP BY 及 HAVING 的 SQL 範例:
-
SQL指令:SELECT TeamID, count(*) as 球員人數, avg(Percentage) as 平均命中率 FROM Player GROUP BY TeamID
意義:每個球隊的球員人數及平均命中率
說明:avg(Percentage) 可以計算命中率平均值,類似的 SQL 聚合函數有 Avg(平均值)、Count(筆數)、Max(最大值)、Min(最小值)、StDev(母群體樣本標準差)、StDevp(母群體標準差)、Sum(總和)、Var(母群體樣本變異數)、VarP(母群體變異數)等。由於這是對於每個球隊的統計數字,所以必須用到群組指令「GROUP BY」。
查詢結果:TeamID |
球員人數 |
平均命中率 |
---|
1 | 6 | 50.61666666666667 |
2 | 1 | 25.88 |
3 | 3 | 44.54333333333333 |
4 | 1 | 65.55 |
5 | 6 | 51.355 |
6 | 2 | 79.975 |
7 | 1 | 65.87 |
-
SQL指令:SELECT TeamID, count(*) as 球員人數 FROM Player GROUP BY TeamID HAVING count(*)>2
意義:每個球隊的球員人數,但只顯示球員人數大於 2 位的資料
說明:avg(Percentage) 可以計算命中率平均值。由於這是對於每個球隊的統計數字,所以必須用到群組指令「GROUP BY」,相關的條件則必須使用「HAVING」來指定。
查詢結果:
以上範例都是只有針對一個資料表來進行檢視查詢,下列的範例則是根據這兩個資料表的關聯性來進行檢視查詢。
-
SQL指令:SELECT Team.Name, Player.Name, Percentage FROM Player, Team WHERE ((Team.Name='台北隊') and (Player.TeamID=Team.ID))
意義:台北隊的球員資料
說明:由於兩個資料表都有 Name 欄位,所以我們必須使用 Team.Name 及 Player.Name 來區分不同資料表的欄位。另外,這兩個資料表的關聯性是由(Player.TeamID=Team.ID) 所建立,所以在後續的範例中,我們會不斷使用這個查詢條件。
查詢結果:Name |
Name |
Percentage |
---|
台北隊 | 陳孜彬 | 50.26 |
台北隊 | 高名揚 | 67.88 |
台北隊 | 李宜揚 | 36.67 |
台北隊 | 林頌華 | 54.77 |
台北隊 | 吳瑞千 | 55.87 |
台北隊 | 吳志銘 | 38.25 |
-
SQL指令:SELECT Team.Name, Player.Name, Percentage FROM Player, Team WHERE (Player.TeamID=Team.ID) and (Team.Name IN ('高雄隊', '台中隊')) ORDER BY Team.Name, Percentage DESC
意義:高雄隊和台中隊的射手排行榜
查詢結果:Name |
Name |
Percentage |
---|
台中隊 | 陳江村 | 48.76 |
台中隊 | 許嘉晉 | 47.65 |
台中隊 | 林惠娟 | 37.22 |
高雄隊 | 洪鵬翔 | 88.97 |
高雄隊 | 許文豪 | 70.98 |
-
SQL指令:SELECT Team.Name as 球隊名稱, Team.WinNo as 贏場次數, count(*) as 球員人數, max(Percentage) as 最高命中率, min(Percentage) as 最低命中率, avg(Percentage) as 平均命中率 FROM Player, Team WHERE ((Player.TeamID=Team.ID)) GROUP BY Team.Name, Team.WinNo
意義:每個球隊的相關統計數字
說明:由於這是對於每個球隊的統計數字,所以必須用到群組指令「GROUP BY」。同時由於被選取的欄位中,Team.Name 和 Team.WinNo 都沒有用到任何聚合函數,所以在 GROUP BY 之後也必須要加上這兩個欄位。
查詢結果:球隊名稱 |
贏場次數 |
球員人數 |
最高命中率 |
最低命中率 |
平均命中率 |
---|
台中隊 | 10 | 3 | 48.76 | 37.22 | 44.54333333333333 |
台北隊 | 12 | 6 | 67.88 | 36.67 | 50.61666666666667 |
台南隊 | 17 | 6 | 67.45 | 33.33 | 51.355 |
南投隊 | 12 | 1 | 65.55 | 65.55 | 65.55 |
高雄隊 | 16 | 2 | 88.97 | 70.98 | 79.975 |
新竹隊 | 7 | 1 | 25.88 | 25.88 | 25.88 |
澎湖隊 | 11 | 1 | 65.87 | 65.87 | 65.87 |
另外還有一些使用 SQL 來檢視資料的範例,可見 asp/example/database/selectQuery01.asp,請讀者自行試看看。
下一小節將說明如何使用 SQL 指令來對資料庫進行新增、修改、刪除資料等動作。
JScript 程式設計與應用:用於伺服器端的 ASP 環境