數據庫語句 半天就學會

SQL 指令
SELECT
DISTINCT
WHERE
AND OR
IN
BETWEEN
LIKE
ORDER BY
函數
COUNT
GROUP BY
HAVING
ALIAS
表格鏈接
外部鏈接
CONCATENATE
SUBSTRING
TRIM
表格處理
CREATE TABLE
CONSTRAINT
NOT NULL
UNIQUE
CHECK
主鍵
外來鍵
CREATE VIEW
CREATE INDEX
ALTER TABLE
DROP TABLE
TRUNCATE TABLE
INSERT INTO
UPDATE
DELETE FROM
進階 SQL
UNION
UNION ALL
INTERSECT
MINUS
子查詢
EXISTS
CASE
算排名
非常簡單明瞭的SQL語句教程,看了這篇文本,非常利於大家對數據庫的學習。
算中位數
算總合百分比
算累積總合百分比
SQL 語法
無論您是一位 SQL 的新手,或是一位只是需要對 SQL 複習一下的資料倉儲業界老將,您
就來對地方了。這個 SQL 教材網站列出常用的 SQL 指令,包含以下幾個部分:
♦ SQL 指令: SQL 如何被用來儲存、讀取、以及處理數據庫之中的資料。
♦ 表格處理: SQL 如何被用來處理數據庫中的表格。
♦ 進階 SQL: 介紹 SQL 進階概念,以及如何用 SQL 來執行一些較複雜的運算。
♦ SQL 語法: 這一頁列出所有在這個教材中被提到的 SQL 語法。
對於每一個指令,我們將會先列出及解釋這個指令的語法,然後用一個例子來讓讀者瞭解這
個指令是如何被運用的。當您讀完了這個網站的所有教材後,您將對 SQL 的語法會有一個
大致上的瞭解。另外,您將能夠正確地運用 SQL 來由數據庫中獲取信息。筆者本身的經驗
是,雖然要對 SQL 有很透徹的瞭解並不是一朝一夕可以完成的,可是要對 SQL 有個基本
的瞭解並不難。希望在看完這個網站後,您也會有同樣的想法。
SQL 指令
SELECT
是用來做什麼的呢?一個最常用的方式是將資料從數據庫中的表格內選出。從這一句回答
中,我們馬上可以看到兩個關鍵字: 從 (FROM) 數據庫中的表格內選出 (SELECT)。(表
格是一個數據庫內的結構,它的目的是儲存資料。在表格處理這一部分中,我們會提到如何
使用 SQL 來設定表格。) 我們由這裏可以看到最基本的 SQL 架構:
SELECT "欄位名" FROM "表格名"
我們用以下的例子來看看實際上是怎麼用的。假設我們有以下這個表格:
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
若要選出所有的店名 (store_Name),我們就打入:
SELECT store_name FROM Store_Information
結果:
store_name
Los Angeles
San Diego
Los Angeles
Boston
我們一次可以讀取好幾個欄位,也可以同時由好幾個表格中選資料。
DISTINCT
SELECT 指令讓我們能夠讀取表格中一個或數個欄位的所有資料。這將把所有的資料都抓
出,無論資料值有無重複。在資料處理中,我們會經常碰到需要找出表格內的不同資料值的
情況。換句話說,我們需要知道這個表格/欄位內有哪些不同的值,而每個值出現的次數並
不重要。這要如何達成呢?在 SQL 中,這是很容易做到的。我們只要在 SELECT 後加上
一個 DISTINCT 就可以了。DISTINCT 的語法如下:
SELECT DISTINCT "欄位名"
FROM "表格名"
舉例來說,若要在以下的表格,Store_Information,找出所有不同的店名時,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT DISTINCT store_name FROM Store_Information
結果:
store_name
Los Angeles
San Diego
Boston
WHERE
我們並不一定每一次都要將表格內的資料都完全抓出。在許多時候,我們會需要選擇性地抓
資料。就我們的例子來說,我們可能只要抓出營業額超過 $1,000 的資料。要做到這一點,
我們就需要用到 WHERE 這個指令。這個指令的語法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "條件"
若我們要由以下的表格抓出營業額超過 $1,000 的資料,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT store_name
FROM Store_Information
WHERE Sales > 1000
結果:
store_name
Los Angeles
AND OR
在上一頁中,我們看到 WHERE 指令可以被用來由表格中有條件地選取資料。 這個條件
可能是簡單的 (像上一頁的例子),也可能是複雜的。複雜條件是由二或多個簡單條件透過
AND 或是 OR 的連接而成。一個 SQL 語句中可以有無限多個簡單條件的存在。
複雜條件的語法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "簡單條件"
{[AND|OR] "簡單條件"}+
{}+ 代表{}之內的情況會發生一或多次。在這裏的意思就是 AND 加簡單條件及 OR 加簡
單條件的情況可以發生一或多次。另外,我們可以用 () 來代表條件的先後次序。
舉例來說,我們若要在 Store_Information 表格中選出所有 Sales 高於 $1,000 或是 Sales
在 $500 及 $275 之間的資料的話,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
San Francisco
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT store_name
FROM Store_Information
WHERE Sales > 1000
OR (Sales < 500 AND Sales > 275)
結果:
store_name
Los Angeles
San Francisco
IN
在 SQL 中,在兩個情況下會用到 IN 這個指令;這一頁將介紹其中之一:與 WHERE 有
關的那一個情況。在這個用法下,我們事先已知道至少一個我們需要的值,而我們將這些知
道的值都放入 IN 這個子句。 IN 指令的語法爲下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" IN ('值一', '值二', ...)
在括號內可以有一或多個值,而不同值之間由逗點分開。值可以是數目或是文字。若在括號
內只有一個值,那這個子句就等於
WHERE "欄位名" = '值一'
舉例來說,若我們要在 Store_Information 表格中找出所有含蓋 Los Angeles 或 San Diego
的資料,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
San Francisco
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT *
FROM Store_Information
WHERE store_name IN ('Los Angeles', 'San Diego')
結果:
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
BETWEEN
IN 這個指令可以讓我們依照一或數個不連續 (discrete) 的值的限制之內抓出資料庫中的
值,而 BETWEEN 則是讓我們可以運用一個範圍 (range) 內抓出資料庫中的值。BETWEEN
這個子句的語法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" BETWEEN '值一' AND '值二'
這將選出欄位值包含在值一及值二之間的每一筆資料。
舉例來說,若我們要由 Store_Information 表格中找出所有介於 January 6, 1999 及 January
10, 1999 中的資料,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
San Francisco
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT *
FROM Store_Information
WHERE Date BETWEEN 'Jan-06-1999' AND 'Jan-10-1999'
請讀者注意:在不同的數據庫中,日期的儲存法可能會有所不同。在這裏我們選擇了其中一
種儲存法。
結果:
store_name
Sales
Date
San Diego
$250
Jan-07-1999
San Francisco
$300
Jan-08-1999
Boston
$700
Jan-08-1999
LIKE
LIKE 是另一個在 WHERE 子句中會用到的指令。基本上, LIKE 能讓我們依據一個模式
(pattern) 來找出我們要的資料。相對來說,在運用 IN 的時候,我們完全地知道我們需要的
條件;在運用 BETWEEN 的時候,我們則是列出一個範圍。 LIKE 的語法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" LIKE {模式}
{模式} 經常包括野卡 (wildcard). 以下是幾個例子:
'A_Z': 所有以 'A' 起頭,另一個任何值的字原,且以 'Z' 爲結尾的字符串。 'ABZ' 和 'A2Z'
都符合這一個模式,而 'AKKZ' 並不符合 (因爲在 A 和 Z 之間有兩個字原,而不是一個
字原)。
'ABC%': 所有以 'ABC' 起頭的字符串。舉例來說,'ABCD' 和 'ABCABC' 都符合這個模式。
'%XYZ': 所有以 'XYZ' 結尾的字符串。舉例來說,'WXYZ' 和 'ZZXYZ' 都符合這個模式。
'%AN%': 所有含有 'AN'這個模式的字符串。舉例來說, 'LOS ANGELES' 和 'SAN
FRANCISCO' 都符合這個模式。
我們將以上最後一個例子用在我們的 Store_Information 表格上:
Store_Information 表格
store_name
Sales
Date
LOS ANGELES
$1500
Jan-05-1999
SAN DIEGO
$250
Jan-07-1999
SAN FRANCISCO
$300
Jan-08-1999
BOSTON
$700
Jan-08-1999
我們就鍵入,
SELECT *
FROM Store_Information
WHERE store_name LIKE '%AN%'
結果:
store_name
Sales
Date
LOS ANGELES
$1500
Jan-05-1999
SAN FRANCISCO
$300
Jan-08-1999
SAN DIEGO
$250
Jan-07-1999
ORDER BY
到目前爲止,我們已學到如何藉由 SELECT 及 WHERE 這兩個指令將資料由表格中抓出。
不過我們尚未提到這些資料要如何排列。這其實是一個很重要的問題。事實上,我們經常需
要能夠將抓出的資料做一個有系統的顯示。這可能是由小往大 (ascending) 或是由大往小
(descending)。在這種情況下,我們就可以運用 ORDER BY 這個指令來達到我們的目的。
ORDER BY 的語法如下:
SELECT "欄位名"
FROM "表格名"
[WHERE "條件"]
ORDER BY "欄位名" [ASC, DESC]
[] 代表 WHERE 子句不是一定需要的。不過,如果 WHERE 子句存在的話,它是在
ORDER BY 子句之前。 ASC 代表結果會以由小往大的順序列出,而 DESC 代表結果會以
由大往小的順序列出。如果兩者皆沒有被寫出的話,那我們就會用 ASC。
我們可以照好幾個不同的欄位來排順序。在這個情況下, ORDER BY 子句的語法如下(假
設有兩個欄位):
ORDER BY "欄位一" [ASC, DESC], "欄位二" [ASC, DESC]
若我們對這兩個欄位都選擇由小往大的話,那這個子句就會造成結果是依據 "欄位一" 由小
往大排。若有好幾筆資料 "欄位一" 的值相等,那這幾筆資料就依據 "欄位二" 由小往大排。
舉例來說,若我們要依照 Sales 欄位的由大往小列出 Store_Information 表格中的資料,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
San Francisco
$300
an-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT store_name, Sales, Date
FROM Store_Information
ORDER BY Sales DESC
結果:
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
Boston
$700
Jan-08-1999
San Francisco
$300
Jan-08-1999
San Diego
$250
Jan-07-1999
在以上的例子中,我們用欄位名來指定排列順序的依據。除了欄位名外,我們也可以用欄位
的順序 (依據 SQL 句中的順序)。在 SELECT 後的第一個欄位爲 1,第二個欄位爲 2,以
此類推。在上面這個例子中,我們用以下這句 SQL 可以達到完全一樣的效果:
SELECT store_name, Sales, Date
FROM Store_Information
ORDER BY 2 DESC
函數
既然數據庫中有許多資料都是已數字的型態存在,一個很重要的用途就是要能夠對這些數字
做一些運算,例如將它們總合起來,或是找出它們的平均值。SQL 有提供一些這一類的函
數。它們是:
AVG (平均)
COUNT (計數)
MAX (最大值)
MIN (最小值)
SUM (總合)
運用函數的語法是:
SELECT "函數名"("欄位名")
FROM "表格名"
舉例來說,若我們要由我們的範例表格中求出 Sales 欄位的總合,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT SUM(Sales) FROM Store_Information
結果:
SUM(Sales)
$2750
$2750 代表所有 Sales 欄位的總合: $1500 + $250 + $300 + $700.
除了函數的運用外,SQL 也可以做簡單的數學運算,例如加(+)和減(-)。對於文字類的資料,
SQL 也有好幾個文字處理方面的函數,例如文字相連 (concatenation),文字修整 (trim),以
及子字符串 (substring)。不同的數據庫對這些函數有不同的語法,所以最好是參考您所用數
據庫的信息,來確定在那個數據庫中,這些函數是如何被運用的。
COUNT
在上一頁有提到, COUNT 是函數之一。由於它的使用廣泛,我們在這裏特別提出來討論。
基本上, COUNT 讓我們能夠數出在表格中有多少筆資料被選出來。它的語法是:
SELECT COUNT("欄位名")
FROM "表格名"
舉例來說,若我們要找出我們的範例表格中有幾筆 store_name 欄不是空白的資料時,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT COUNT(store_name)
FROM Store_Information
WHERE store_name is not NULL
結果:
Count(store_name)
4
"is not NULL" 是 "這個欄位不是空白" 的意思。
COUNT 和 DISTINCT 經常被合起來使用,目的是找出表格中有多少筆不同的資料 (至於
這些資料實際上是什麼並不重要)。舉例來說,如果我們要找出我們的表格中有多少個不同
的 store_name,我們就鍵入,
SELECT COUNT(DISTINCT store_name)
FROM Store_Information
結果:
Count(DISTINCT store_name)
3
GROUP BY
我們現在回到函數上。記得我們用 SUM 這個指令來算出所有的 Sales (營業額)吧!如果我
們的需求變成是要算出每一間店 (store_name) 的營業額 (sales),那怎麼辦呢?在這個情況
下,我們要做到兩件事:第一,我們對於 store_name 及 Sales 這兩個欄位都要選出。第二,
我們需要確認所有的 sales 都要依照各個 store_name 來分開算。這個語法爲:
SELECT "欄位 1", SUM("欄位 2")
FROM "表格名"
GROUP BY "欄位 1"
在我們的範例上,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們就鍵入,
SELECT store_name, SUM(Sales)
FROM Store_Information
GROUP BY store_name
結果:
store_name SUM(Sales)
Los Angeles $1800
San Diego $250
Boston $700
當我們選不只一個欄位,且其中至少一個欄位有包含函數的運用時,我們就需要用到
GROUP BY 這個指令。在這個情況下,我們需要確定我們有 GROUP BY 所有其他的欄位。
換句話說,除了有包括函數的欄位外,我們都需要將其放在 GROUP BY 的子句中。
HAVING
那我們如何對函數產生的值來設定條件呢?舉例來說,我們可能只需要知道哪些店的營業額
有超過 $1,500。在這個情況下,我們不能使用 WHERE 的指令。那要怎麼辦呢?很幸運地,
SQL 有提供一個 HAVING 的指令,而我們就可以用這個指令來達到這個目標。 HAVING
子句通常是在一個 SQL 句子的最後。一個含有 HAVING 子句的 SQL 並不一定要包含
GROUP BY 子句。HAVING 的語法如下:
SELECT "欄位 1", SUM("欄位 2")
FROM "表格名"
GROUP BY "欄位 1"
HAVING (函數條件)
請讀者注意: 如果被 SELECT 的只有函數欄, 那就不需要 GROUP BY 子句。
在我們 Store_Information 表格這個例子中,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
若我們要找出 Sales 大於 $1,500 的 store_name,我們就鍵入,
SELECT store_name, SUM(sales)
FROM Store_Information
GROUP BY store_name
HAVING SUM(sales) > 1500
結果:
store_name SUM(Sales)
Los Angeles $1800
ALIAS
接下來,我們討論 alias (別名) 在 SQL 上的用處。最常用到的別名有兩種:欄位別名及表
格別名。
簡單地來說,欄位別名的目的是爲了讓 SQL 產生的結果易讀。在之前的例子中,每當我們
有營業額總合時,欄位名都是 SUM(sales)。雖然在這個情況下沒有什麼問題,可是如果這
個欄位不是一個簡單的總合,而是一個複雜的計算,那欄位名就沒有這麼易懂了。若我們用
欄位別名的話,就可以確認結果中的欄位名是簡單易懂的。
第二種別名是表格別名。要給一個表格取一個別名,只要在 FROM 子句中的表格名後空一
格,然後再列出要用的表格別名就可以了。這在我們要用 SQL 由數個不同的表格中獲取資
料時是很方便的。這一點我們在之後談到連接 (join) 時會看到。
我們先來看一下欄位別名和表格別名的語法:
SELECT "表格別名"."欄位 1" "欄位別名"
FROM "表格名" "表格別名"
基本上,這兩種別名都是放在它們要替代的物件後面,而它們中間由一個空白分開。我們繼
續使用 Store_Information 這個表格來做例子:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
我們用跟 SQL GROUP BY 那一頁一樣的例子。這裏的不同處是我們加上了欄位別名以及
表格別名:
SELECT A1.store_name Store, SUM(A1.Sales) "Total Sales"
FROM Store_Information A1
GROUP BY A1.store_name
結果:
Store Total Sales
Los Angeles $1800
San Diego $250
Boston $700
在結果中,資料本身沒有不同。不同的是欄位的標題。這是運用欄位別名的結果。在第二個
欄位上,原本我們的標題是 "Sum(Sales)",而現在我們有一個很清楚的 "Total Sales"。很明
顯地, "Total Sales" 能夠比 "Sum(Sales)" 更精確地闡述這個欄位的含意。用表格別名的好
處在這裏並沒有顯現出來,不過這在 下一頁就會很清楚了。
表格鏈接
現在我們介紹連接(join)的概念。要了解連接,我們需要用到許多我們之前已介紹過的指令。
我們先假設我們有以下的兩個表格,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
而我們要知道每一區 (region_name) 的營業額 (sales)。 Geography 這個表格告訴我們每一
區有哪些店,而 Store_Information 告訴我們每一個店的營業額。若我們要知道每一區的營
業額,我們需要將這兩個不同表格中的資料串聯起來。當我們仔細瞭解這兩個表格後,我們
會發現它們可經由一個相同的欄位,store_name,連接起來。我們先將 SQL 句列出,之後
再討論每一個子句的意義:
SELECT A1.region_name REGION, SUM(A2.Sales) SALES
FROM Geography A1, Store_Information A2
WHERE A1.store_name = A2.store_name
GROUP BY A1.region_name
結果:
REGION SALES
East $700
West $2050
在第一行中,我們告訴 SQL 去選出兩個欄位:第一個欄位是 Geography 表格中的
region_name 欄位 (我們取了一個別名叫做 REGION);第二個欄位是 Store_Information 表
格中的 sales 欄位 (別名爲 SALES)。請注意在這裏我們有用到表格別名:Geography 表格
的別名是 A1,Store_Information 表格的別名是 A2。若我們沒有用表格別名的話,第一行
就會變成
SELECT Geography.region_name REGION, SUM(Store_Information.Sales) SALES
很明顯地,這就複雜多了。在這裏我們可以看到表格別名的功用:它能讓 SQL 句容易被了
解,尤其是這個 SQL 句含蓋好幾個不同的表格時。
接下來我們看第三行,就是 WHERE 子句。這是我們闡述連接條件的地方。在這裏,我們
要確認 Geography 表格中 store_name 欄位的值與 Store_Information 表格中 store_name
欄位的值是相等的。這個 WHERE 子句是一個連接的靈魂人物,因爲它的角色是確定兩個
表格之間的連接是正確的。如果 WHERE 子句是錯誤的,我們就極可能得到一個笛卡兒連
接 (Cartesian join)。笛卡兒連接會造成我們得到所有兩個表格每兩行之間所有可能的組合。
在這個例子中,笛卡兒連接會讓我們得到 4 x 4 = 16 行的結果。
外部鏈接
之前我們看到的左連接 (left join),又稱內部連接 (inner join)。在這個情況下,要兩個表格
內都有同樣的值,那一筆資料纔會被選出。那如果我們想要列出一個表格中每一筆的資料,
無論它的值在另一個表格中有沒有出現,那該怎麼辦呢?在這個時候,我們就需要用到 SQL
OUTER JOIN (外部連接) 的指令。
外部連接的語法是依數據庫的不同而有所不同的。舉例來說,在 Oracle 上,我們會在
WHERE 子句中要選出所有資料的那個表格之後加上一個 "(+)" 來代表說這個表格中的所
有資料我們都要。
假設我們有以下的兩個表格:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
我們需要知道每一間店的營業額。如果我們用一個普通的連接,我們將會漏失掉 'New York'
這個店,因爲它並不存在於 Store_Information 這個表格。所以,在這個情況下,我們需要
用外部連接來串聯這兩個表格:
SELECT A1.store_name, SUM(A2.Sales) SALES
FROM Georgraphy A1, Store_Information A2
WHERE A1.store_name = A2.store_name (+)
GROUP BY A1.store_name
我們在這裏是使用了 Oracle 的外部連接語法。
結果:
store_name SALES
Boston $700
New York
Los Angeles $1800
San Diego $250
請注意: 當第二個表格沒有相對的資料時, SQL 會傳回 NULL 值。在這一個例子中, 'New
York' 並不存在於 Store_Information 表格,所以它的 "SALES" 欄位是 NULL.
CONCATENATE
有的時候,我們有需要將由不同欄位獲得的資料串連在一起。每一種數據庫都有提供方法來
達到這個目的:
MySQL: CONCAT()
Oracle: CONCAT(), ||
SQL Server: +
CONCAT() 的語法如下:
CONCAT(字符串 1, 字符串 2, 字符串 3, ...): 將字符串 1、字符串 2、字符串 3,等字符串連
在一起。請注意,Oracle 的 CONCAT()只允許兩個參數;換言之,一次只能將兩個字符串串
連起來。不過,在 Oracle 中,我們可以用'||'來一次串連多個字符串。
來看一個例子。假設我們有以下的表格:
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
例子 1:
MySQL/Oracle:
SELECT CONCAT(region_name,store_name) FROM Geography
WHERE store_name = 'Boston';
結果:
'EastBoston'
例子 2:
Oracle:
SELECT region_name || ' ' || store_name FROM Geography
WHERE store_name = 'Boston';
結果:
'East Boston'
例子 3:
SQL Server:
SELECT region_name + ' ' + store_name FROM Geography
WHERE store_name = 'Boston';
結果:
'East Boston'
SUBSTRING
SQL 中的 substring 函數是用來抓出一個欄位資料中的其中一部分。這個函數的名稱在不同
的數據庫中不完全一樣:
MySQL: SUBSTR(), SUBSTRING()
Oracle: SUBSTR()
SQL Server: SUBSTRING()
最常用到的方式如下 (在這裏我們用 SUBSTR()爲例):
SUBSTR(str,pos): 由<str>中,選出所有從第<pos>位置開始的字符。請注意,這個語法不適
用於 SQL Server 上。
SUBSTR(str,pos,len): 由<str>中的第<pos>位置開始,選出接下去的<len>個字符。
假設我們有以下的表格:
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
例 1:
SELECT SUBSTR(store_name, 3)
FROM Geography
WHERE store_name = 'Los Angeles';
結果:
's Angeles'
例 2:
SELECT SUBSTR(store_name,2,4)
FROM Geography
WHERE store_name = 'San Diego';
結果:
'an D'
TRIM
SQL 中的 TRIM 函數是用來移除掉一個字符串中的字頭或字尾。最常見的用途是移除字首
或字尾的空白。這個函數在不同的數據庫中有不同的名稱:
MySQL: TRIM(), RTRIM(), LTRIM()
Oracle: RTRIM(), LTRIM()
SQL Server: RTRIM(), LTRIM()
各種 trim 函數的語法如下:
TRIM([[位置] [要移除的字符串] FROM ] 字符串): [位置] 的可能值爲 LEADING (起頭),
TRAILING (結尾), or BOTH (起頭及結尾)。 這個函數將把 [要移除的字符串] 從字符串的起
頭、結尾,或是起頭及結尾移除。如果我們沒有列出 [要移除的字符串] 是什麼的話,那空
白就會被移除。
LTRIM(字符串): 將所有字符串起頭的空白移除。
RTRIM(字符串): 將所有字符串結尾的空白移除。
例 1:
SELECT TRIM(' Sample ');
結果:
'Sample'
例 2:
SELECT LTRIM(' Sample ');
結果:
'Sample '
例 3:
SELECT RTRIM(' Sample ');
結果:
' Sample'
表格處理
CREATE TABLE
表格是數據庫中儲存資料的基本架構。在絕大部份的情況下,數據庫廠商不可能知道您需要
如何儲存您的資料,所以通常您會需要自己在數據庫中建立表格。雖然許多數據庫工具可以
讓您在不需用到 SQL 的情況下建立表格,不過由於表格是一個最基本的架構,我們決定包
括 CREATE TABLE 的語法在這個網站中。
在我們跳入 CREATE TABLE 的語法之前,我們最好先對錶格這個東西有些多一點的瞭解。
表格被分爲欄位 (column) 及列位 (row)。每一列代表一筆資料,而每一欄代表一筆資料的
一部份。舉例來說,如果我們有一個記載顧客資料的表格,那欄位就有可能包括姓、名、地
址、城市、國家、生日‧‧‧等等。當我們對錶格下定義時,我們需要註明欄位的標題,以及那
個欄位的資料種類。
那,資料種類是什麼呢?資料可能是以許多不同的形式存在的。它可能是一個整數 (例如
1),、一個實數 (例如 0.55)、一個字符串 (例如 'sql')、一個日期/時間 (例如 '2000-JAN-25
03:22:22')、或甚至是以二進法 (binary) 的狀態存在。當我們在對一個表格下定義時,我們
需要對每一個欄位的資料種類下定義。 (例如 '姓' 這個欄位的資料種類是 char(50)──代
表這是一個 50 個字符的字符串)。我們需要注意的一點是不同的數據庫有不同的資料種類,
所以在對錶格做出定義之前最好先參考一下數據庫本身的說明。
CREATE TABLE 的語法是:
CREATE TABLE "表格名"
("欄位 1" "欄位 1 資料種類",
"欄位 2" "欄位 2 資料種類",
... )
若我們要建立我們上面提過的顧客表格,我們就鍵入以下的 SQL:
CREATE TABLE customer
(First_Name char(50),
Last_Name char(50),
Address char(50),
City char(50),
Country char(25),
Birth_Date date)
CONSTRAINT
我們可以限制哪一些資料可以存入表格中。這些限制可以在表格初創時藉由 CREATE
TABLE 語句來指定,或是之後藉由 ALTER TABLE 語句來指定。
常見的限制有以下幾種:
NOT NULL
UNIQUE
CHECK
主鍵 (Primary Key)
外來鍵 (Foreign Key)
以下對這幾種限制分別做個介紹:
NOT NULL
在沒有做出任何限制的情況下,一個欄位是允許有 NULL 值得。如果我們不允許一個欄位
含有 NULL 值,我們就需要對那個欄位做出 NOT NULL 的指定。
舉例來說,在以下的語句中,
CREATE TABLE Customer
(SID integer NOT NULL,
Last_Name varchar (30) NOT NULL,
First_Name varchar(30));
"SID" 和 "Last_Name" 這兩個欄位是不允許有 NULL 值,而 "First_Name" 這個欄位是可
以有 NULL 值得。
UNIQUE
UNIQUE 限制是保證一個欄位中的所有資料都是有不一樣的值。
舉例來說,在以下的語句中,
CREATE TABLE Customer
(SID integer Unique,
Last_Name varchar (30),
First_Name varchar(30));
"SID" 欄位不能有重複值存在,而 "Last_Name" 及 "First_Name" 這兩個欄位則是允許有重
復值存在。
請注意,一個被指定爲主鍵的欄位也一定會含有 UNIQUE 的特性。相對來說,一個
UNIQUE 的欄位並不一定會是一個主鍵。
CHECK
CHECK 限制是保證一個欄位中的所有資料都是符合某些條件。
舉例來說,在以下的語句中,
CREATE TABLE Customer
(SID integer CHECK (SID > 0),
Last_Name varchar (30),
First_Name varchar(30));
"SID" 攔只能包含大於 0 的整數。
請注意,CHECK 限制目前尚未被執行於 MySQL 數據庫上。
主鍵 and 外來鍵 將於下兩頁中討論。
主鍵
主鍵 (Primary Key) 中的每一筆資料都是表格中的唯一值。換言之,它是用來獨一無二地確
認一個表格中的每一行資料。主鍵可以是原本資料內的一個欄位,或是一個人造欄位 (與原
本資料沒有關係的欄位)。主鍵可以包含一或多個欄位。當主鍵包含多個欄位時,稱爲組合
鍵 (Composite Key)。
主鍵可以在建置新表格時設定 (運用 CREATE TABLE 語句),或是以改變現有的表格架構
方式設定 (運用 ALTER TABLE)。
以下舉幾個在建置新表格時設定主鍵的方式:
MySQL:
CREATE TABLE Customer
(SID integer,
Last_Name varchar(30),
First_Name varchar(30),
PRIMARY KEY (SID));
Oracle:
CREATE TABLE Customer
(SID integer PRIMARY KEY,
Last_Name varchar(30),
First_Name varchar(30));
SQL Server:
CREATE TABLE Customer
(SID integer PRIMARY KEY,
Last_Name varchar(30),
First_Name varchar(30));
以下則是以改變現有表格架構來設定主鍵的方式:
MySQL:
ALTER TABLE Customer ADD PRIMARY KEY (SID);
Oracle:
ALTER TABLE Customer ADD PRIMARY KEY (SID);
SQL Server:
ALTER TABLE Customer ADD PRIMARY KEY (SID);
請注意,在用 ALTER TABLE 語句來添加主鍵之前,我們需要確認被用來當做主鍵的欄位是
設定爲 『NOT NULL』 ;也就是說,那個欄位一定不能沒有資料。
外來鍵
外來鍵是一個(或數個)指向另外一個表格主鍵的欄位。外來鍵的目的是確定資料的參考完整
性(referential integrity)。換言之,只有被准許的資料值纔會被存入數據庫內。
舉例來說,假設我們有兩個表格:一個 CUSTOMER 表格,裏面記錄了所有顧客的資料;
另一個 ORDERS 表格,裏面記錄了所有顧客訂購的資料。在這裏的一個限制,就是所有的
訂購資料中的顧客,都一定是要跟在 CUSTOMER 表格中存在。在這裏,我們就會在
ORDERS 表格中設定一個外來鍵,而這個外來鍵是指向 CUSTOMER 表格中的主鍵。這樣
一來,我們就可以確定所有在 ORDERS 表格中的顧客都存在 CUSTOMER 表格中。換句
話說,ORDERS 表格之中,不能有任何顧客是不存在於 CUSTOMER 表格中的資料。
這兩個表格的結構將會是如下:
CUSTOMER 表格
欄位名
性質
SID
主鍵
Last_Name
First_Name
ORDERS 表格
欄位名
性質
Order_ID
主鍵
Order_Date
Customer_SID
外來鍵
Amount
在以上的例子中,ORDERS 表格中的 customer_SID 欄位是一個指向 CUSTOMERS 表格
中 SID 欄位的外來鍵。
以下列出幾個在建置 ORDERS 表格時指定外來鍵的方式:
MySQL:
CREATE TABLE ORDERS
(Order_ID integer,
Order_Date date,
Customer_SID integer,
Amount double,
Primary Key (Order_ID),
Foreign Key (Customer_SID) references CUSTOMER(SID));
Oracle:
CREATE TABLE ORDERS
(Order_ID integer primary key,
Order_Date date,
Customer_SID integer references CUSTOMER(SID),
Amount double);
SQL Server:
CREATE TABLE ORDERS
(Order_ID integer primary key,
Order_Date datetime,
Customer_SID integer references CUSTOMER(SID),
Amount double);
以下的例子則是藉着改變表格架構來指定外來鍵。這裏假設 ORDERS 表格已經被建置,而
外來鍵尚未被指定:
MySQL:
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(sid);
Oracle:
ALTER TABLE ORDERS
ADD
(CONSTRAINT
fk_orders1)
FOREIGN
KEY
(customer_sid)
REFERENCES
CUSTOMER(sid);
SQL Server:
ALTER TABLE ORDERS
ADD FOREIGN KEY (customer_sid) REFERENCES CUSTOMER(sid);
CREATE VIEW
視觀表 (Views) 可以被當作是虛擬表格。它跟表格的不同是,表格中有實際儲存資料,而
視觀表是建立在表格之上的一個架構,它本身並不實際儲存資料。
建立一個視觀表的語法如下:
CREATE VIEW "VIEW_NAME" AS "SQL 語句"
"SQL 語句" 可以是任何一個我們在這個教材中有提到的 SQL。
來看一個例子。假設我們有以下的表格:
TABLE Customer
(First_Name char(50),
Last_Name char(50),
Address char(50),
City char(50),
Country char(25),
Birth_Date date)
若要在這個表格上建立一個包括 First_Name, Last_Name, 和 Country 這三個欄位的視
觀表,我們就打入,
CREATE VIEW V_Customer
AS SELECT First_Name, Last_Name, Country
FROM Customer
現在,我們就有一個叫做 V_Customer 的視觀表:
View V_Customer
(First_Name char(50),
Last_Name char(50),
Country char(25))
我們也可以用視觀表來連接兩個表格。在這個情況下,使用者就可以直接由一個視觀表中找
出她要的信息,而不需要由兩個不同的表格中去做一次連接的動作。假設有以下的兩個表格:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
我們就可以用以下的指令來建一個包括每個地區 (region) 銷售額 (sales) 的視觀表:
CREATE VIEW V_REGION_SALES
AS SELECT A1.region_name REGION, SUM(A2.Sales) SALES
FROM Geography A1, Store_Information A2
WHERE A1.store_name = A2.store_name
GROUP BY A1.region_name
這就給我們有一個名爲 V_REGION_SALES 的視觀表。這個視觀表包含不同地區的銷售
哦。如果我們要從這個視觀表中獲取資料,我們就打入,
SELECT * FROM V_REGION_SALES
結果:
REGION SALES
East $700
West $2050
CREATE INDEX
索引 (Index) 可以幫助我們從表格中快速地找到需要的資料。舉例來說,假設我們要在一本
園藝書中找如何種植青椒的訊息。若這本書沒有索引的話,那我們是必須要從頭開始讀,直
到我們找到有關種直青椒的地方爲止。若這本書有索引的話,我們就可以先去索引找出種植
青椒的信息是在哪一頁,然後直接到那一頁去閱讀。很明顯地,運用索引是一種有效且省時
的方式。
從數據庫表格中尋找資料也是同樣的原理。如果一個表格沒有索引的話,數據庫系統就需要
將整個表格的資料讀出 (這個過程叫做'table scan')。若有適當的索引存在,數據庫系統就可
以先由這個索引去找出需要的資料是在表格的什麼地方,然後直接去那些地方抓資料。這樣
子速度就快多了。
因此,在表格上建立索引是一件有利於系統效率的事。一個索引可以涵蓋一或多個欄位。建
立索引的語法如下:
CREATE INDEX "INDEX_NAME" ON "TABLE_NAME" (COLUMN_NAME)
現在假設我們有以下這個表格,
TABLE Customer
(First_Name char(50),
Last_Name char(50),
Address char(50),
City char(50),
Country char(25),
Birth_Date date)
若我們要在 Last_Name 這個欄位上建一個索引,我們就打入以下的指令,
CREATE INDEX IDX_CUSTOMER_LAST_NAME
on CUSTOMER (Last_Name)
我們要在 City 及 Country 這兩個欄位上建一個索引,我們就打入以下的指令,
CREATE INDEX IDX_CUSTOMER_LOCATION
on CUSTOMER (City, Country)
索引的命名並沒有一個固定的方式。通常會用的方式是在名稱前加一個字首,例如
"IDX_" ,來避免與數據庫中的其他物件混淆。另外,在索引名之內包括表格名及欄位名也
是一個好的方式。
請讀者注意,每個數據庫會有它本身的 CREATE INDEX 語法,而不同數據庫的語法會有
不同。因此,在下指令前,請先由數據庫使用手冊中確認正確的語法。
ALTER TABLE
在表格被建立在數據庫中後,我們常常會發現,這個表格的結構需要有所改變。常見的改變
如下:
加一個欄位
刪去一個欄位
改變欄位名稱
改變欄位的資料種類
以上列出的改變並不是所有可能的改變。ALTER TABLE 也可以被用來作其他的改變,例如
改變主鍵定義。
ALTER TABLE 的語法如下:
ALTER TABLE "table_name"
[改變方式]
[改變方式] 的詳細寫法會依我們想要達到的目標而有所不同。再以上列出的改變中,[改變
方式] 如下:
加一個欄位: ADD "欄位 1" "欄位 1 資料種類"
刪去一個欄位: DROP "欄位 1"
改變欄位名稱: CHANGE "原本欄位名" "新欄位名" "新欄位名資料種類"
改變欄位的資料種類: MODIFY "欄位 1" "新資料種類"
以下我們用在 CREATE TABLE 一頁建出的 customer 表格來當作例子:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Address
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
第一,我們要加入一個叫做 "gender" 的欄位。這可以用以下的指令達成:
ALTER table customer add Gender char(1)
這個指令執行後的表格架構是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Address
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
接下來,我們要把 "Address" 欄位改名爲 "Addr"。這可以用以下的指令達成:
ALTER table customer change Address Addr char(50)
這個指令執行後的表格架構是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
再來,我們要將 "Addr" 欄位的資料種類改爲 char(30)。這可以用以下的指令達成:
ALTER table customer modify Addr char(30)
這個指令執行後的表格架構是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(30)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
最後,我們要刪除 "Gender" 欄位。這可以用以下的指令達成:
ALTER table customer drop Gender
這個指令執行後的表格架構是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(30)
City
char(50)
Country
char(25)
Birth_Date
date
DROP TABLE
有時候我們會決定我們需要從數據庫中清除一個表格。事實上,如果我們不能這樣做的話,
那將會是一個很大的問題,因爲數據庫管理師 (Database Administrator -- DBA) 勢必無法對
數據庫做有效率的管理。還好,SQL 有提供一個 DROP TABLE 的語法來讓我們清除表格。
DROP TABLE 的語法是:
DROP TABLE "表格名"
我們如果要清除在上一頁中建立的顧客表格,我們就鍵入:
DROP TABLE customer.
TRUNCATE TABLE
有時候我們會需要清除一個表格中的所有資料。要達到者個目的,一種方式是我們在 上一
頁看到 的 DROP TABLE 指令。不過這樣整個表格就消失,而無法再被用了。另一種方式
就是運用 TRUNCATE TABLE 的指令。在這個指令之下,表格中的資料會完全消失,可是
表格本身會繼續存在。 TRUNCATE TABLE 的語法爲下:
TRUNCATE TABLE "表格名"
所以,我們如果要清除在 SQL Create Table 那一頁建立的顧客表格之內的資料,我們就鍵
入:
TRUNCATE TABLE customer.
INSERT INTO
到目前爲止,我們學到了將如何把資料由表格中取出。但是這些資料是如果進入這些表格的
呢?這就是這一頁 (INSERT INTO) 和下一頁 (UPDATE) 要討論的。
基本上,我們有兩種作法可以將資料輸入表格中內。一種是一次輸入一筆,另一種是一次輸
入好幾筆。我們先來看一次輸入一筆的方式。
依照慣例,我們先介紹語法。一次輸入一筆資料的語法如下:
INSERT INTO "表格名" ("欄位 1", "欄位 2", ...)
VALUES ("值 1", "值 2", ...)
假設我們有一個架構如下的表格:
Store_Information 表格
Column Name
Data Type
store_name
char(50)
Sales
float
Date
datetime
而我們要加以下的這一筆資料進去這個表格:在 January 10, 1999,Los Angeles 店有 $900
的營業額。我們就打入以下的 SQL 語句:
INSERT INTO Store_Information (store_name, Sales, Date)
VALUES ('Los Angeles', 900, 'Jan-10-1999')
第二種 INSERT INTO 能夠讓我們一次輸入多筆的資料。跟上面剛的例子不同的是,現在我
們要用 SELECT 指令來指明要輸入表格的資料。如果您想說,這是不是說資料是從另一個
表格來的,那您就想對了。一次輸入多筆的資料的語法是:
INSERT INTO "表格 1" ("欄位 1", "欄位 2", ...)
SELECT "欄位 3", "欄位 4", ...
FROM "表格 2"
以上的語法是最基本的。這整句 SQL 也可以含有 WHERE、 GROUP BY、及 HAVING 等
子句,以及表格連接及別名等等。
舉例來說,若我們想要將 1998 年的營業額資料放入 Store_Information 表格,而我們知道
資料的來源是可以由 Sales_Information 表格取得的話,那我們就可以鍵入以下的 SQL:
INSERT INTO Store_Information (store_name, Sales, Date)
SELECT store_name, Sales, Date
FROM Sales_Information
WHERE Year(Date) = 1998
在這裏,我用了 SQL Server 中的函數來由日期中找出年。不同的數據庫會有不同的語法。
舉個例來說,在 Oracle 上,您將會使用 WHERE to_char(date,'yyyy')=1998。
UPDATE
我們有時候可能會需要修改表格中的資料。在這個時候,我們就需要用到 UPDATE 指令。
這個指令的語法是:
UPDATE "表格名"
SET "欄位 1" = [新值]
WHERE {條件}
最容易瞭解這個語法的方式是透過一個例子。假設我們有以下的表格:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
我們發現說 Los Angeles 在 01/08/1999 的營業額實際上是 $500,而不是表格中所儲存的
$300,因此我們用以下的 SQL 來修改那一筆資料:
UPDATE Store_Information
SET Sales = 500
WHERE store_name = "Los Angeles"
AND Date = "Jan-08-1999"
現在表格的內容變成:
Store_Information 表格
store_name Sales Date
Los Angeles $1500 Jan-05-1999
San Diego $250 Jan-07-1999
Los Angeles $500 Jan-08-1999
Boston $700 Jan-08-1999
在這個例子中,只有一筆資料符合 WHERE 子句中的條件。如果有多筆資料符合條件的話,
每一筆符合條件的資料都會被修改的。
我們也可以同時修改好幾個欄位。這語法如下:
UPDATE "表格"
SET "欄位 1" = [值 1], "欄位 2" = [值 2]
WHERE {條件}
DELETE FROM
在某些情況下,我們會需要直接由數據庫中去除一些資料。這可以藉由 DELETE FROM 指
令來達成。它的語法是:
DELETE FROM "表格名"
WHERE {條件}
以下我們用個實例說明。假設我們有以下這個表格:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
而我們需要將有關 Los Angeles 的資料全部去除。在這裏我們可以用以下的 SQL 來達到這
個目的:
DELETE FROM Store_Information
WHERE store_name = "Los Angeles"
現在表格的內容變成:
Store_Information 表格
store_name
Sales
Date
San Diego
$250
Jan-07-1999
Boston
$700
Jan-08-1999
進階 SQL
在這一部分,我們將介紹以下的 SQL 概念及關鍵字:
SQL UNION
SQL UNION ALL
SQL INTERSECT
SQL MINUS
SQL Subquery
SQL EXISTS
SQL CASE
我們並介紹如何用 SQL 來做出以下的運算:
排名 (Rank)
中位數 (Median)
累積總計 (Running Total)
總合百分比 (Percent to Total)
累積總合百分比 (Cumulative Percent to Total)
UNION
UNION 指令的目的是將兩個 SQL 語句的結果合併起來。從這個角度來看, UNION 跟
JOIN 有些許類似,因爲這兩個指令都可以由多個表格中擷取資料。 UNION 的一個限制是
兩個 SQL 語句所產生的欄位需要是同樣的資料種類。另外,當我們用 UNION 這個指令
時,我們只會看到不同的資料值 (類似 SELECT DISTINCT)。
UNION 的語法如下:
[SQL 語句 1]
UNION
[SQL 語句 2]
假設我們有以下的兩個表格,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Internet_Sales 表格
Date
Sales
Jan-07-1999
$250
Jan-10-1999
$535
Jan-11-1999
$320
Jan-12-1999
$750
而我們要找出來所有有營業額 (sales) 的日子。要達到這個目的,我們用以下的 SQL 語句:
SELECT Date FROM Store_Information
UNION
SELECT Date FROM Internet_Sales
結果:
Date
Jan-05-1999
Jan-07-1999
Jan-08-1999
Jan-10-1999
Jan-11-1999
Jan-12-1999
有一點值得注意的是,如果我們在任何一個 SQL 語句 (或是兩句都一起) 用 "SELECT
DISTINCT Date" 的話,那我們會得到完全一樣的結果。
UNION ALL
UNION ALL 這個指令的目的也是要將兩個 SQL 語句的結果合併在一起。 UNION ALL 和
UNION 不同之處在於 UNION ALL 會將每一筆符合條件的資料都列出來,無論資料值有無
重複。
UNION ALL 的語法如下:
[SQL 語句 1]
UNION ALL
[SQL 語句 2]
我們用和上一頁同樣的例子來顯示出 UNION ALL 和 UNION 的不同。同樣假設我們有以
下兩個表格,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Internet_Sales 表格
Date
Sales
Jan-07-1999
$250
Jan-10-1999
$535
Jan-11-1999
$320
Jan-12-1999
$750
而我們要找出有店面營業額以及網絡營業額的日子。要達到這個目的,我們用以下的 SQL
語句:
SELECT Date FROM Store_Information
UNION ALL
SELECT Date FROM Internet_Sales
結果:
Date
Jan-05-1999
Jan-07-1999
Jan-08-1999
Jan-08-1999
Jan-07-1999
Jan-10-1999
Jan-11-1999
Jan-12-1999
INTERSECT
和 UNION 指令類似, INTERSECT 也是對兩個 SQL 語句所產生的結果做處理的。不同
的地方是, UNION 基本上是一個 OR (如果這個值存在於第一句或是第二句,它就會被選
出),而 INTERSECT 則比較像 AND (這個值要存在於第一句和第二句纔會被選出)。
UNION 是聯集,而 INTERSECT 是交集。
INTERSECT 的語法如下:
[SQL 語句 1]
INTERSECT
[SQL 語句 2]
假設我們有以下的兩個表格,
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Internet_Sales 表格
Date
Sales
Jan-07-1999
$250
Jan-10-1999
$535
Jan-11-1999
$320
Jan-12-1999
$750
而我們要找出哪幾天有店面交易和網絡交易。要達到這個目的,我們用以下的 SQL 語句:
SELECT Date FROM Store_Information
INTERSECT
SELECT Date FROM Internet_Sales
結果:
Date
Jan-07-1999
請注意,在 INTERSECT 指令下,不同的值只會被列出一次。
MINUS
MINUS 指令是運用在兩個 SQL 語句上。它先找出第一個 SQL 語句所產生的結果,然後
看這些結果有沒有在第二個 SQL 語句的結果中。如果有的話,那這一筆資料就被去除,而
不會在最後的結果中出現。如果第二個 SQL 語句所產生的結果並沒有存在於第一個 SQL
語句所產生的結果內,那這筆資料就被拋棄。
MINUS 的語法如下:
[SQL 語句 1]
MINUS
[SQL 語句 2]
我們繼續使用一樣的例子:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Internet_Sales 表格
Date
Sales
Jan-07-1999
$250
Jan-10-1999
$535
Jan-11-1999
$320
Jan-12-1999
$750
而我們要知道有哪幾天是有店面營業額而沒有網絡營業額的。要達到這個目的,我們用以下
的 SQL 語句:
SELECT Date FROM Store_Information
MINUS
SELECT Date FROM Internet_Sales
結果:
Date
Jan-05-1999
Jan-08-1999
"Jan-05-1999", "Jan-07-1999", and "Jan-08-1999" 是 "SELECT Date FROM Store_Information"
所產生的結果。在這裏面, "Jan-07-1999" 是存在於 "SELECT Date FROM Internet_Sales" 所
產生的結果中。因此 "Jan-07-1999" 並不在最後的結果中。
請注意,在 MINUS 指令下,不同的值只會被列出一次。
子查詢
我們可以在一個 SQL 語句中放入另一個 SQL 語句。當我們在 WHERE 子句或 HAVING
子句中插入另一個 SQL 語句時,我們就有一個子查詢 (subquery) 的架構。 子查詢的作用
是什麼呢?第一,它可以被用來連接表格。另外,有的時候子查詢是唯一能夠連接兩個表格
的方式。
子查詢的語法如下:
SELECT "欄位 1"
FROM "表格"
WHERE "欄位 2" [比較運算素]
(SELECT "欄位 1"
FROM "表格"
WHERE [條件])
[比較運算素] 可以是相等的運算素,例如 =, >, <, >=, <=. 這也可以是一個對文字的運算素,
例如 "LIKE"。綠色的部分代表外查詢,紅色的部分代表內查詢。
我們就用剛剛在闡述 SQL 連接時用過的例子:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500 Jan-05-1999
San Diego
$250 Jan-07-1999
Los Angeles
$300 Jan-08-1999
Boston
$700 Jan-08-1999
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
我們要運用 subquery 來找出所有在西部的店的營業額。我們可以用下面的 SQL 來達到我
們的目的:
SELECT SUM(Sales) FROM Store_Information
WHERE Store_name IN
(SELECT store_name FROM Geography
WHERE region_name = 'West')
結果:
SUM(Sales)
2050
在這個例子中,我們並沒有直接將兩個表格連接起來,然後由此直接算出每一間西區店面的
營業額。我們做的是先找出哪些店是在西區的,然後再算出這些店的營業額總共是多少。
在以上的例子,內部查詢本身與外部查詢沒有關係。這一類的子查詢稱爲『簡單子查詢』
(Simple Subquery)。如果內部查詢是要利用到外部查詢提到的表格中的欄位,那這個字查詢
就被稱爲『相關子查詢』 (Correlated Subquery)。以下是一個相關子查詢的例子:
SELECT SUM(a1.Sales) FROM Store_Information a1
WHERE a1.Store_name IN
(SELECT store_name FROM Geography a2
WHERE a2.store_name = a1.store_name)
紅色部分即是外部查詢提到的表格中的欄位。
EXISTS
在上一頁中,我們用 IN 來連接內查詢和外查詢。另外有數個方式,例如 >, <, 及 =,
都可以用來連接內查詢和外查詢。 EXISTS 也是其中一種方式。這一頁我們將討論 EXISTS
的用法。
基本上, EXISTS 是用來測試內查詢有沒有產生任何結果。如果有的話,系統就會執行外
查詢中的 SQL。若是沒有的話,那整個 SQL 語句就不會產生任何結果。
EXISTS 的語法是:
SELECT "欄位 1"
FROM "表格 1"
WHERE EXISTS
(SELECT *
FROM "表格 2"
WHERE [條件])
在內查詢中,我們並不一定要用 * 來選出所有的欄位。我們也可以選擇表格 2 中的任何欄
位。這兩種做法最後的結果是一樣的。
來看一個例子。假設我們有以下的兩個表格:
Store_Information 表格
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
Los Angeles
$300
Jan-08-1999
Boston
$700
Jan-08-1999
Geography 表格
region_name
store_name
East
Boston
East
New York
West
Los Angeles
West
San Diego
而我們打入的 SQL 是:
SELECT SUM(Sales) FROM Store_Information
WHERE EXISTS
(SELECT * FROM Geography
WHERE region_name = 'West')
我們會得到以下的答案:
SUM(Sales)
2750
乍看之下,這個答案似乎不太正確,因爲內查詢有包含一個 [region_name = 'West'] 的條件,
可是最後的答案並沒有包含這個條件。實際上,這並沒有問題。在這個例子中,內查詢產生
了超過一筆的資料,所以 EXISTS 的條件成立,所以外查詢被執行。而外查詢本身並沒有
包含 [region_name = 'West'] 這個條件。
CASE
CASE 是 SQL 用來做爲 if-then-else 之類邏輯的關鍵字。 CASE 的語法如下:
SELECT CASE ("欄位名")
WHEN "條件 1" THEN "結果 1"
WHEN "條件 2" THEN "結果 2"
...
[ELSE "結果 N"]
END
FROM "表格名"
"條件" 可以是一個數值或是公式。 ELSE 子句則並不是必須的。
在我們的 Store_Information 中
Store_Information 表格
store_name Sales Date
Los Angeles $1500 Jan-05-1999
San Diego $250 Jan-07-1999
San Francisco $300 Jan-08-1999
Boston $700 Jan-08-1999
若我們要將 'Los Angeles' 的 Sales 數值乘以 2,以及將 'San Diego' 的 Sales 數值乘以 1.5,
我們就鍵入以下的 SQL:
SELECT store_name, CASE store_name
WHEN 'Los Angeles' THEN Sales * 2
WHEN 'San Diego' THEN Sales * 1.5
ELSE Sales
END
"New Sales",
Date
FROM Store_Information
"New Sales" 是用到 CASE 那個欄位的欄位名。
結果:
store_name
New Sales
Date
Los Angeles
$3000 Jan-05-1999
San Diego
$375 Jan-07-1999
San Francisco
$300 Jan-08-1999
Boston
$700 Jan-08-1999
算排名
列出每一行的排名是一個常見的需求,可惜 SQL 並沒有一個很直接的方式達到這個需求。
要以 SQL 列出排名,基本的概念是要做一個表格自我連結 (self join),將結果依序列出,
然後算出每一行之前 (包含那一行本身) 有多少行數。這樣講讀者聽得可能有點困惑,所以
最好的方式是用一個實例來介紹。假設我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要找出每一行的排名,我們就打入以下的 SQL 語句:
SELECT a1.Name, a1.Sales, COUNT(a2.sales) Sales_Rank
FROM Total_Sales a1, Total_Sales a2
WHERE a1.Sales <= a2.Sales or (a1.Sales=a2.Sales and a1.Name = a2.Name)
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;
結果:
Name Sales Sales_Rank
Greg 50 1
Sophia 40 2
Stella 20 3
Jeff 20 3
Jennifer 15 5
John 10 6
我們先來看 WHERE 子句。在字句的第一部分 (a1.Sales <= a2.Sales),我們算出有多少筆資
料 Sales 欄位的值是比自己本身的值小或是相等。如果在 Sales 欄位中沒有同樣大小的資
料,那這部分的 WHERE 子句本身就可以產生出正確的排名。
子句的第二部分,(a1.Sales=a2.Sales and a1.Name = a2.Name),則是讓我們在 Sales 欄位中
有同樣大小的資料時 (像 Stella 及 Jeff 這兩筆資料),仍然能夠產生正確的排名。
算中位數
要算出中位數,我們必須要能夠達成以下幾個目標:
將資料依序排出,並找出每一行資料的排名。
找出『中間』的排名爲何。舉例來說,如果總共有 9 筆資料,那中間排名就是 5 (有 4 筆
資料比第 5 筆資料大,有 4 筆資料比第 5 筆資料小)。
找出中間排名資料的值。
來看看以下的例子。假設我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要找出中位數,我們就鍵入:
SELECT Sales Median FROM
(SELECT a1.Name, a1.Sales, COUNT(a1.Sales) Rank
FROM Total_Sales a1, Total_Sales a2
WHERE a1.Sales < a2.Sales OR (a1.Sales=a2.Sales AND a1.Name <= a2.Name)
group by a1.Name, a1.Sales
order by a1.Sales desc) a3
WHERE Rank = (SELECT (COUNT(*)+1) DIV 2 FROM Total_Sales);
結果:
Median
20
讀者將會發現,第 2 行到第 6 行是跟產生 排名 的語句完全一樣。第 7 行則是算出中間
的排名。DIV 是在 MySQL 中算出商的方式。在不同的數據庫中會有不同的方式求商。第 1
行則是列出排名中間的資料值。
算累積總計
算出累積總計是一個常見的需求,可惜以 SQL 並沒有一個很直接的方式達到這個需求。要
以 SQL 算出累積總計,基本上的概念與列出排名類似:第一是先做個表格自我連結 (self
join),然後將結果依序列出。在做列出排名時,我們算出每一行之前 (包含那一行本身) 有
多少行數;而在做累積總計時,我們則是算出每一行之前 (包含那一行本身) 的總合。
來看看以下的例子。假設我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要算出累積總計,我們就鍵入:
SELECT a1.Name, a1.Sales, SUM(a2.Sales) Running_Total
FROM Total_Sales a1, Total_Sales a2
WHERE a1.Sales <= a2.sales or (a1.Sales=a2.Sales and a1.Name = a2.Name)
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;
結果:
Name Sales Running_Total
Greg 50 50
Sophia 40 90
Stella 20 110
Jeff 20 130
Jennifer 15 145
John 10 155
在以上的 SQL 語句中, WHERE 子句和 ORDER BY 子句讓我們能夠在有重複值時能夠
算出正確的累積總計。
算總合百分比
要用 SQL 算出總合百分比,我們需要用到算排名和累積總計的概念,以及運用子查詢的做
法。在這裏,我們把子查詢放在外部查詢的 SELECT 子句中。讓我們來看以下的例子:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要算出總合百分比,我們鍵入:
SELECT a1.Name, a1.Sales, a1.Sales/(SELECT SUM(Sales) FROM Total_Sales) Pct_To_Total
FROM Total_Sales a1, Total_Sales a2
WHERE a1.Sales <= a2.sales or (a1.Sales=a2.Sales and a1.Name = a2.Name)
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;
結果:
Name Sales Pct_To_Total
Greg 50 0.3226
Sophia 40 0.2581
Stella 20 0.1290
Jeff 20 0.1290
Jennifer 15 0.0968
John 10 0.0645
"SELECT SUM(Sales) FROM Total_Sales" 這一段子查詢是用來算出總合。總合算出後,我
們就能夠將每一行一一除以總合來求出每一行的總合百分比。
算累積總合百分比
要用 SQL 累積總合百分比算出,我們運用類似總合百分比的概念。兩者的不同處在於在這
個情況下,我們要算出到目前爲止的累積總合是所有總合的百分之幾,而不是光看每一筆資
料是所有總合的百分之幾。讓我們來看看以下的例子:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要算出累積總合百分比,我們鍵入:
SELECT a1.Name, a1.Sales, SUM(a2.Sales)/(SELECT SUM(Sales) FROM Total_Sales)
Pct_To_Total
FROM Total_Sales a1, Total_Sales a2
WHERE a1.Sales <= a2.sales or (a1.Sales=a2.Sales and a1.Name = a2.Name)
GROUP BY a1.Name, a1.Sales
ORDER BY a1.Sales DESC, a1.Name DESC;
結果:
Name Sales Pct_To_Total
Greg 50 0.3226
Sophia 40 0.5806
Stella 20 0.7097
Jeff 20 0.8387
Jennifer 15 0.9355
John 10 1.0000
"SELECT SUM(Sales) FROM Total_Sales" 這一段子查詢是用來算出總合。我們接下來用累
積總計 "SUM(a2.Sales)" 除以總合來求出每一行的累積總合百分比。
SQL 語法
Select
SELECT "欄位" FROM "表格名"
Distinct
SELECT DISTINCT "欄位"
FROM "表格名"
Where
SELECT "欄位"
FROM "表格名"
WHERE "condition"
And/Or
SELECT "欄位"
FROM "表格名"
WHERE "簡單條件"
{[AND|OR] "簡單條件"}+
In
SELECT "欄位"
FROM "表格名"
WHERE "欄位" IN ('值 1', '值 2', ...)
Between
SELECT "欄位"
FROM "表格名"
WHERE "欄位" BETWEEN '值 1' AND '值 2'
Like
SELECT "欄位"
FROM "表格名"
WHERE "欄位" LIKE {模式}
Order By
SELECT "欄位"
FROM "表格名"
[WHERE "條件"]
ORDER BY "欄位" [ASC, DESC]
Count
SELECT COUNT("欄位")
FROM "表格名"
Group By
SELECT "欄位 1", SUM("欄位 2")
FROM "表格名"
GROUP BY "欄位 1"
Having
SELECT "欄位 1", SUM("欄位 2")
FROM "表格名"
GROUP BY "欄位 1"
HAVING (函數條件)
Create Table
CREATE TABLE "表格名"
("欄位 1" "欄位 1 資料種類",
"欄位 2" "欄位 2 資料種類"",
... )
Drop Table
DROP TABLE "表格名"
Truncate Table
TRUNCATE TABLE "表格名"
Insert Into
INSERT INTO "表格名" ("欄位 1", "欄位 2", ...)
VALUES ("值 1", "值 2", ...)
Update
UPDATE "表格名"
SET "欄位 1" = [新值]
WHERE {條件}
Delete From
DELETE FROM "表格名"
WHERE {條件}
來自:http://www.1keydata.com/tw/sql/sql.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章