無(wú)論您是一位 SQL 的新手,或是一位只是需要對(duì) SQL 復(fù)習(xí)一下的資料倉(cāng)儲(chǔ)業(yè)界老將,您就來(lái)對(duì)地方了。這個(gè) SQL 教材網(wǎng)站列出常用的 SQL 指令,包含以下幾個(gè)部分:
♦ SQL 指令: SQL 如何被用來(lái)儲(chǔ)存、讀取、以及處理數(shù)據(jù)庫(kù)之中的資料。
♦ 表格處理: SQL 如何被用來(lái)處理數(shù)據(jù)庫(kù)中的表格。
♦ 進(jìn)階 SQL: 介紹 SQL 進(jìn)階概念,以及如何用 SQL 來(lái)執(zhí)行一些較復(fù)雜的運(yùn)算。
♦ SQL 語(yǔ)法: 這一頁(yè)列出所有在這個(gè)教材中被提到的 SQL 語(yǔ)法。
對(duì)于每一個(gè)指令,我們將會(huì)先列出及解釋這個(gè)指令的語(yǔ)法,然后用一個(gè)例子來(lái)讓讀者了解這個(gè)指令是如何被運(yùn)用的。當(dāng)您讀完了這個(gè)網(wǎng)站的所有教材后,您將對(duì) SQL 的語(yǔ)法會(huì)有一個(gè)大致上的了解。另外,您將能夠正確地運(yùn)用 SQL 來(lái)由數(shù)據(jù)庫(kù)中獲取信息。筆者本身的經(jīng)驗(yàn)是,雖然要對(duì) SQL 有很透徹的了解并不是一朝一夕可以完成的,可是要對(duì) SQL 有個(gè)基本的了解并不難。希望在看完這個(gè)網(wǎng)站后,您也會(huì)有同樣的想法。
SQL指令
SELECT
是用來(lái)做什么的呢?一個(gè)最常用的方式是將資料從數(shù)據(jù)庫(kù)中的表格內(nèi)選出。從這一句回答中,我們馬上可以看到兩個(gè)關(guān)鍵字: 從 (FROM) 數(shù)據(jù)庫(kù)中的表格內(nèi)選出 (SELECT)。(表格是一個(gè)數(shù)據(jù)庫(kù)內(nèi)的結(jié)構(gòu),它的目的是儲(chǔ)存資料。在表格處理這一部分中,我們會(huì)提到如何使用 SQL 來(lái)設(shè)定表格。) 我們由這里可以看到最基本的 SQL 架構(gòu):
SELECT "欄位名" FROM "表格名"
我們用以下的例子來(lái)看看實(shí)際上是怎么用的。假設(shè)我們有以下這個(gè)表格:
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
結(jié)果:
store_name
Los Angeles
San Diego
Los Angeles
Boston
我們一次可以讀取好幾個(gè)欄位,也可以同時(shí)由好幾個(gè)表格中選資料。
DISTINCT
SELECT 指令讓我們能夠讀取表格中一個(gè)或數(shù)個(gè)欄位的所有資料。這將把所有的資料都抓出,無(wú)論資料值有無(wú)重復(fù)。在資料處理中,我們會(huì)經(jīng)常碰到需要找出表格內(nèi)的不同資料值的情況。換句話說(shuō),我們需要知道這個(gè)表格/欄位內(nèi)有哪些不同的值,而每個(gè)值出現(xiàn)的次數(shù)并不重要。這要如何達(dá)成呢?在 SQL 中,這是很容易做到的。我們只要在 SELECT 后加上一個(gè) DISTINCT 就可以了。DISTINCT 的語(yǔ)法如下:
SELECT DISTINCT "欄位名"
FROM "表格名"
舉例來(lái)說(shuō),若要在以下的表格,Store_Information,找出所有不同的店名時(shí),
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
結(jié)果:
store_name
Los Angeles
San Diego
Boston
WHERE
我們并不一定每一次都要將表格內(nèi)的資料都完全抓出。在許多時(shí)候,我們會(huì)需要選擇性地抓資料。就我們的例子來(lái)說(shuō),我們可能只要抓出營(yíng)業(yè)額超過(guò) $1,000 的資料。要做到這一點(diǎn),我們就需要用到 WHERE 這個(gè)指令。這個(gè)指令的語(yǔ)法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "條件"
若我們要由以下的表格抓出營(yíng)業(yè)額超過(guò) $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
結(jié)果:
store_name
Los Angeles
AND OR
在上一頁(yè)中,我們看到 WHERE 指令可以被用來(lái)由表格中有條件地選取資料。 這個(gè)條件可能是簡(jiǎn)單的 (像上一頁(yè)的例子),也可能是復(fù)雜的。復(fù)雜條件是由二或多個(gè)簡(jiǎn)單條件透過(guò) AND 或是 OR 的連接而成。一個(gè) SQL 語(yǔ)句中可以有無(wú)限多個(gè)簡(jiǎn)單條件的存在。
復(fù)雜條件的語(yǔ)法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "簡(jiǎn)單條件"
{[AND|OR] "簡(jiǎn)單條件"}+
{}+ 代表{}之內(nèi)的情況會(huì)發(fā)生一或多次。在這里的意思就是 AND 加簡(jiǎn)單條件及 OR 加簡(jiǎn)單條件的情況可以發(fā)生一或多次。另外,我們可以用 () 來(lái)代表?xiàng)l件的先后次序。
舉例來(lái)說(shuō),我們?nèi)粢?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)
結(jié)果:
store_name
Los Angeles
San Francisco
IN
在 SQL 中,在兩個(gè)情況下會(huì)用到 IN 這個(gè)指令;這一頁(yè)將介紹其中之一:與 WHERE 有關(guān)的那一個(gè)情況。在這個(gè)用法下,我們事先已知道至少一個(gè)我們需要的值,而我們將這些知道的值都放入 IN 這個(gè)子句。 IN 指令的語(yǔ)法為下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" IN ('值一', '值二', ...)
在括號(hào)內(nèi)可以有一或多個(gè)值,而不同值之間由逗點(diǎn)分開。值可以是數(shù)目或是文字。若在括號(hào)內(nèi)只有一個(gè)值,那這個(gè)子句就等于
WHERE "欄位名" = '值一'
舉例來(lái)說(shuō),若我們要在 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')
結(jié)果:
store_name
Sales
Date
Los Angeles
$1500
Jan-05-1999
San Diego
$250
Jan-07-1999
BETWEEN
IN 這個(gè)指令可以讓我們依照一或數(shù)個(gè)不連續(xù) (discrete) 的值的限制之內(nèi)抓出資料庫(kù)中的值,而 BETWEEN 則是讓我們可以運(yùn)用一個(gè)范圍 (range) 內(nèi)抓出資料庫(kù)中的值。BETWEEN 這個(gè)子句的語(yǔ)法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" BETWEEN '值一' AND '值二'
這將選出欄位值包含在值一及值二之間的每一筆資料。
舉例來(lái)說(shuō),若我們要由 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'
請(qǐng)讀者注意:在不同的數(shù)據(jù)庫(kù)中,日期的儲(chǔ)存法可能會(huì)有所不同。在這里我們選擇了其中一種儲(chǔ)存法。
結(jié)果:
store_name
Sales
Date
San Diego
$250
Jan-07-1999
San Francisco
$300
Jan-08-1999
Boston
$700
Jan-08-1999
LIKE
LIKE 是另一個(gè)在 WHERE 子句中會(huì)用到的指令。基本上, LIKE 能讓我們依據(jù)一個(gè)模式 (pattern) 來(lái)找出我們要的資料。相對(duì)來(lái)說(shuō),在運(yùn)用 IN 的時(shí)候,我們完全地知道我們需要的條件;在運(yùn)用 BETWEEN 的時(shí)候,我們則是列出一個(gè)范圍。 LIKE 的語(yǔ)法如下:
SELECT "欄位名"
FROM "表格名"
WHERE "欄位名" LIKE {模式}
{模式} 經(jīng)常包括野卡 (wildcard). 以下是幾個(gè)例子:
'A_Z': 所有以 'A' 起頭,另一個(gè)任何值的字原,且以 'Z' 為結(jié)尾的字符串。 'ABZ' 和 'A2Z' 都符合這一個(gè)模式,而 'AKKZ' 并不符合 (因?yàn)樵?A 和 Z 之間有兩個(gè)字原,而不是一個(gè)字原)。
'ABC%': 所有以 'ABC' 起頭的字符串。舉例來(lái)說(shuō),'ABCD' 和 'ABCABC' 都符合這個(gè)模式。
'%XYZ': 所有以 'XYZ' 結(jié)尾的字符串。舉例來(lái)說(shuō),'WXYZ' 和 'ZZXYZ' 都符合這個(gè)模式。
'%AN%': 所有含有 'AN'這個(gè)模式的字符串。舉例來(lái)說(shuō), 'LOS ANGELES' 和 'SAN FRANCISCO' 都符合這個(gè)模式。
我們將以上最后一個(gè)例子用在我們的 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%'
結(jié)果:
store_name
Sales
Date
LOS ANGELES
$1500
Jan-05-1999
SAN FRANCISCO
$300
Jan-08-1999
SAN DIEGO
$250
Jan-07-1999
ORDER BY
到目前為止,我們已學(xué)到如何藉由 SELECT 及 WHERE 這兩個(gè)指令將資料由表格中抓出。不過(guò)我們尚未提到這些資料要如何排列。這其實(shí)是一個(gè)很重要的問題。事實(shí)上,我們經(jīng)常需要能夠?qū)⒆コ龅馁Y料做一個(gè)有系統(tǒng)的顯示。這可能是由小往大 (ascending) 或是由大往小(descending)。在這種情況下,我們就可以運(yùn)用 ORDER BY 這個(gè)指令來(lái)達(dá)到我們的目的。
ORDER BY 的語(yǔ)法如下:
SELECT "欄位名"
FROM "表格名"
[WHERE "條件"]
ORDER BY "欄位名" [ASC, DESC]
[] 代表 WHERE 子句不是一定需要的。不過(guò),如果 WHERE 子句存在的話,它是在 ORDER BY 子句之前。 ASC 代表結(jié)果會(huì)以由小往大的順序列出,而 DESC 代表結(jié)果會(huì)以由大往小的順序列出。如果兩者皆沒有被寫出的話,那我們就會(huì)用 ASC。
我們可以照好幾個(gè)不同的欄位來(lái)排順序。在這個(gè)情況下, ORDER BY 子句的語(yǔ)法如下(假設(shè)有兩個(gè)欄位):
ORDER BY "欄位一" [ASC, DESC], "欄位二" [ASC, DESC]
若我們對(duì)這兩個(gè)欄位都選擇由小往大的話,那這個(gè)子句就會(huì)造成結(jié)果是依據(jù) "欄位一" 由小往大排。若有好幾筆資料 "欄位一" 的值相等,那這幾筆資料就依據(jù) "欄位二" 由小往大排。
舉例來(lái)說(shuō),若我們要依照 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
結(jié)果:
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
在以上的例子中,我們用欄位名來(lái)指定排列順序的依據(jù)。除了欄位名外,我們也可以用欄位的順序 (依據(jù) SQL 句中的順序)。在 SELECT 后的第一個(gè)欄位為 1,第二個(gè)欄位為 2,以此類推。在上面這個(gè)例子中,我們用以下這句 SQL 可以達(dá)到完全一樣的效果:
SELECT store_name, Sales, Date
FROM Store_Information
ORDER BY 2 DESC
函數(shù)
既然數(shù)據(jù)庫(kù)中有許多資料都是已數(shù)字的型態(tài)存在,一個(gè)很重要的用途就是要能夠?qū)@些數(shù)字做一些運(yùn)算,例如將它們總合起來(lái),或是找出它們的平均值。SQL 有提供一些這一類的函數(shù)。它們是:
AVG (平均)
COUNT (計(jì)數(shù))
MAX (最大值)
MIN (最小值)
SUM (總合)
運(yùn)用函數(shù)的語(yǔ)法是:
SELECT "函數(shù)名"("欄位名")
FROM "表格名"
舉例來(lái)說(shuō),若我們要由我們的范例表格中求出 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
結(jié)果:
SUM(Sales)
$2750
$2750 代表所有 Sales 欄位的總合: $1500 + $250 + $300 + $700.
除了函數(shù)的運(yùn)用外,SQL 也可以做簡(jiǎn)單的數(shù)學(xué)運(yùn)算,例如加(+)和減(-)。對(duì)于文字類的資料,SQL 也有好幾個(gè)文字處理方面的函數(shù),例如文字相連 (concatenation),文字修整 (trim),以及子字符串 (substring)。不同的數(shù)據(jù)庫(kù)對(duì)這些函數(shù)有不同的語(yǔ)法,所以最好是參考您所用數(shù)據(jù)庫(kù)的信息,來(lái)確定在那個(gè)數(shù)據(jù)庫(kù)中,這些函數(shù)是如何被運(yùn)用的。
COUNT
在上一頁(yè)有提到, COUNT 是函數(shù)之一。由于它的使用廣泛,我們?cè)谶@里特別提出來(lái)討論?;旧希?COUNT 讓我們能夠數(shù)出在表格中有多少筆資料被選出來(lái)。它的語(yǔ)法是:
SELECT COUNT("欄位名")
FROM "表格名"
舉例來(lái)說(shuō),若我們要找出我們的范例表格中有幾筆 store_name 欄不是空白的資料時(shí),
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
結(jié)果:
Count(store_name)
4
"is not NULL" 是 "這個(gè)欄位不是空白" 的意思。
COUNT 和 DISTINCT 經(jīng)常被合起來(lái)使用,目的是找出表格中有多少筆不同的資料 (至于這些資料實(shí)際上是什么并不重要)。舉例來(lái)說(shuō),如果我們要找出我們的表格中有多少個(gè)不同的 store_name,我們就鍵入,
SELECT COUNT(DISTINCT store_name)
FROM Store_Information
結(jié)果:
Count(DISTINCT store_name)
3
GROUP BY
我們現(xiàn)在回到函數(shù)上。記得我們用 SUM 這個(gè)指令來(lái)算出所有的 Sales (營(yíng)業(yè)額)吧!如果我們的需求變成是要算出每一間店 (store_name) 的營(yíng)業(yè)額 (sales),那怎么辦呢?在這個(gè)情況下,我們要做到兩件事:第一,我們對(duì)于 store_name 及 Sales 這兩個(gè)欄位都要選出。第二,我們需要確認(rèn)所有的 sales 都要依照各個(gè) store_name 來(lái)分開算。這個(gè)語(yǔ)法為:
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
結(jié)果:
store_name SUM(Sales)
Los Angeles $1800
San Diego $250
Boston $700
當(dāng)我們選不只一個(gè)欄位,且其中至少一個(gè)欄位有包含函數(shù)的運(yùn)用時(shí),我們就需要用到 GROUP BY 這個(gè)指令。在這個(gè)情況下,我們需要確定我們有 GROUP BY 所有其他的欄位。換句話說(shuō),除了有包括函數(shù)的欄位外,我們都需要將其放在 GROUP BY 的子句中。
HAVING
那我們?nèi)绾螌?duì)函數(shù)產(chǎn)生的值來(lái)設(shè)定條件呢?舉例來(lái)說(shuō),我們可能只需要知道哪些店的營(yíng)業(yè)額有超過(guò) $1,500。在這個(gè)情況下,我們不能使用 WHERE 的指令。那要怎么辦呢?很幸運(yùn)地,SQL 有提供一個(gè) HAVING 的指令,而我們就可以用這個(gè)指令來(lái)達(dá)到這個(gè)目標(biāo)。 HAVING 子句通常是在一個(gè) SQL 句子的最后。一個(gè)含有 HAVING 子句的 SQL 并不一定要包含 GROUP BY 子句。HAVING 的語(yǔ)法如下:
SELECT "欄位1", SUM("欄位2")
FROM "表格名"
GROUP BY "欄位1"
HAVING (函數(shù)條件)
請(qǐng)讀者注意: 如果被 SELECT 的只有函數(shù)欄, 那就不需要 GROUP BY 子句。
在我們 Store_Information 表格這個(gè)例子中,
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
結(jié)果:
store_name SUM(Sales)
Los Angeles $1800
ALIAS
接下來(lái),我們討論 alias (別名) 在 SQL 上的用處。最常用到的別名有兩種:欄位別名及表格別名。
簡(jiǎn)單地來(lái)說(shuō),欄位別名的目的是為了讓 SQL 產(chǎn)生的結(jié)果易讀。在之前的例子中,每當(dāng)我們有營(yíng)業(yè)額總合時(shí),欄位名都是 SUM(sales)。雖然在這個(gè)情況下沒有什么問題,可是如果這個(gè)欄位不是一個(gè)簡(jiǎn)單的總合,而是一個(gè)復(fù)雜的計(jì)算,那欄位名就沒有這么易懂了。若我們用欄位別名的話,就可以確認(rèn)結(jié)果中的欄位名是簡(jiǎn)單易懂的。
第二種別名是表格別名。要給一個(gè)表格取一個(gè)別名,只要在 FROM 子句中的表格名后空一格,然后再列出要用的表格別名就可以了。這在我們要用 SQL 由數(shù)個(gè)不同的表格中獲取資料時(shí)是很方便的。這一點(diǎn)我們?cè)谥笳劦竭B接 (join) 時(shí)會(huì)看到。
我們先來(lái)看一下欄位別名和表格別名的語(yǔ)法:
SELECT "表格別名"."欄位1" "欄位別名"
FROM "表格名" "表格別名"
基本上,這兩種別名都是放在它們要替代的物件后面,而它們中間由一個(gè)空白分開。我們繼續(xù)使用 Store_Information 這個(gè)表格來(lái)做例子:
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 那一頁(yè)一樣的例子。這里的不同處是我們加上了欄位別名以及表格別名:
SELECT A1.store_name Store, SUM(A1.Sales) "Total Sales"
FROM Store_Information A1
GROUP BY A1.store_name
結(jié)果:
Store Total Sales
Los Angeles $1800
San Diego $250
Boston $700
在結(jié)果中,資料本身沒有不同。不同的是欄位的標(biāo)題。這是運(yùn)用欄位別名的結(jié)果。在第二個(gè)欄位上,原本我們的標(biāo)題是 "Sum(Sales)",而現(xiàn)在我們有一個(gè)很清楚的 "Total Sales"。很明顯地, "Total Sales" 能夠比 "Sum(Sales)" 更精確地闡述這個(gè)欄位的含意。用表格別名的好處在這里并沒有顯現(xiàn)出來(lái),不過(guò)這在 下一頁(yè)就會(huì)很清楚了。
表格鏈接
現(xiàn)在我們介紹連接(join)的概念。要了解連接,我們需要用到許多我們之前已介紹過(guò)的指令。我們先假設(shè)我們有以下的兩個(gè)表格,
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
而我們要知道每一區(qū) (region_name) 的營(yíng)業(yè)額 (sales)。 Geography 這個(gè)表格告訴我們每一區(qū)有哪些店,而 Store_Information 告訴我們每一個(gè)店的營(yíng)業(yè)額。若我們要知道每一區(qū)的營(yíng)業(yè)額,我們需要將這兩個(gè)不同表格中的資料串聯(lián)起來(lái)。當(dāng)我們仔細(xì)了解這兩個(gè)表格后,我們會(huì)發(fā)現(xiàn)它們可經(jīng)由一個(gè)相同的欄位,store_name,連接起來(lái)。我們先將 SQL 句列出,之后再討論每一個(gè)子句的意義:
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
結(jié)果:
REGION SALES
East $700
West $2050
在第一行中,我們告訴 SQL 去選出兩個(gè)欄位:第一個(gè)欄位是 Geography 表格中的 region_name 欄位 (我們?nèi)×艘粋€(gè)別名叫做 REGION);第二個(gè)欄位是 Store_Information 表格中的 sales 欄位 (別名為 SALES)。請(qǐng)注意在這里我們有用到表格別名:Geography 表格的別名是 A1,Store_Information 表格的別名是 A2。若我們沒有用表格別名的話,第一行就會(huì)變成
SELECT Geography.region_name REGION, SUM(Store_Information.Sales) SALES
很明顯地,這就復(fù)雜多了。在這里我們可以看到表格別名的功用:它能讓 SQL 句容易被了解,尤其是這個(gè) SQL 句含蓋好幾個(gè)不同的表格時(shí)。
接下來(lái)我們看第三行,就是 WHERE 子句。這是我們闡述連接條件的地方。在這里,我們要確認(rèn) Geography 表格中 store_name 欄位的值與 Store_Information 表格中 store_name 欄位的值是相等的。這個(gè) WHERE 子句是一個(gè)連接的靈魂人物,因?yàn)樗慕巧谴_定兩個(gè)表格之間的連接是正確的。如果 WHERE 子句是錯(cuò)誤的,我們就極可能得到一個(gè)笛卡兒連接 (Cartesian join)。笛卡兒連接會(huì)造成我們得到所有兩個(gè)表格每?jī)尚兄g所有可能的組合。在這個(gè)例子中,笛卡兒連接會(huì)讓我們得到 4 x 4 = 16 行的結(jié)果。
外部鏈接
之前我們看到的左連接 (left join),又稱內(nèi)部連接 (inner join)。在這個(gè)情況下,要兩個(gè)表格內(nèi)都有同樣的值,那一筆資料才會(huì)被選出。那如果我們想要列出一個(gè)表格中每一筆的資料,無(wú)論它的值在另一個(gè)表格中有沒有出現(xiàn),那該怎么辦呢?在這個(gè)時(shí)候,我們就需要用到 SQL OUTER JOIN (外部連接) 的指令。
外部連接的語(yǔ)法是依數(shù)據(jù)庫(kù)的不同而有所不同的。舉例來(lái)說(shuō),在 Oracle 上,我們會(huì)在 WHERE 子句中要選出所有資料的那個(gè)表格之后加上一個(gè) "(+)" 來(lái)代表說(shuō)這個(gè)表格中的所有資料我們都要。
假設(shè)我們有以下的兩個(gè)表格:
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
我們需要知道每一間店的營(yíng)業(yè)額。如果我們用一個(gè)普通的連接,我們將會(huì)漏失掉 'New York'這個(gè)店,因?yàn)樗⒉淮嬖谟?Store_Information 這個(gè)表格。所以,在這個(gè)情況下,我們需要用外部連接來(lái)串聯(lián)這兩個(gè)表格:
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
我們?cè)谶@里是使用了 Oracle 的外部連接語(yǔ)法。
結(jié)果:
store_name SALES
Boston $700
New York
Los Angeles $1800
San Diego $250
請(qǐng)注意: 當(dāng)?shù)诙€(gè)表格沒有相對(duì)的資料時(shí), SQL 會(huì)傳回 NULL 值。在這一個(gè)例子中, 'New York' 并不存在于 Store_Information 表格,所以它的 "SALES" 欄位是 NULL.
CONCATENATE
有的時(shí)候,我們有需要將由不同欄位獲得的資料串連在一起。每一種數(shù)據(jù)庫(kù)都有提供方法來(lái)達(dá)到這個(gè)目的:
MySQL: CONCAT()
Oracle: CONCAT(), ||
SQL Server: +
CONCAT() 的語(yǔ)法如下:
CONCAT(字符串1, 字符串2, 字符串3, ...): 將字符串1、字符串2、字符串3,等字符串連在一起。請(qǐng)注意,Oracle的CONCAT()只允許兩個(gè)參數(shù);換言之,一次只能將兩個(gè)字符串串連起來(lái)。不過(guò),在Oracle中,我們可以用'||'來(lái)一次串連多個(gè)字符串。
來(lái)看一個(gè)例子。假設(shè)我們有以下的表格:
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';
結(jié)果:
'EastBoston'
例子2:
Oracle:
SELECT region_name || ' ' || store_name FROM Geography
WHERE store_name = 'Boston';
結(jié)果:
'East Boston'
例子3:
SQL Server:
SELECT region_name + ' ' + store_name FROM Geography
WHERE store_name = 'Boston';
結(jié)果:
'East Boston'
SUBSTRING
SQL 中的 substring 函數(shù)是用來(lái)抓出一個(gè)欄位資料中的其中一部分。這個(gè)函數(shù)的名稱在不同的數(shù)據(jù)庫(kù)中不完全一樣:
MySQL: SUBSTR(), SUBSTRING()
Oracle: SUBSTR()
SQL Server: SUBSTRING()
最常用到的方式如下 (在這里我們用SUBSTR()為例):
SUBSTR(str,pos): 由<str>中,選出所有從第<pos>位置開始的字符。請(qǐng)注意,這個(gè)語(yǔ)法不適用于SQL Server上。
SUBSTR(str,pos,len): 由<str>中的第<pos>位置開始,選出接下去的<len>個(gè)字符。
假設(shè)我們有以下的表格:
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';
結(jié)果:
's Angeles'
例2:
SELECT SUBSTR(store_name,2,4)
FROM Geography
WHERE store_name = 'San Diego';
結(jié)果:
'an D'
TRIM
SQL 中的 TRIM 函數(shù)是用來(lái)移除掉一個(gè)字符串中的字頭或字尾。最常見的用途是移除字首或字尾的空白。這個(gè)函數(shù)在不同的數(shù)據(jù)庫(kù)中有不同的名稱:
MySQL: TRIM(), RTRIM(), LTRIM()
Oracle: RTRIM(), LTRIM()
SQL Server: RTRIM(), LTRIM()
各種 trim 函數(shù)的語(yǔ)法如下:
TRIM([[位置] [要移除的字符串] FROM ] 字符串): [位置] 的可能值為 LEADING (起頭), TRAILING (結(jié)尾), or BOTH (起頭及結(jié)尾)。 這個(gè)函數(shù)將把 [要移除的字符串] 從字符串的起頭、結(jié)尾,或是起頭及結(jié)尾移除。如果我們沒有列出 [要移除的字符串] 是什么的話,那空白就會(huì)被移除。
LTRIM(字符串): 將所有字符串起頭的空白移除。
RTRIM(字符串): 將所有字符串結(jié)尾的空白移除。
例 1:
SELECT TRIM(' Sample ');
結(jié)果:
'Sample'
例 2:
SELECT LTRIM(' Sample ');
結(jié)果:
'Sample '
例 3:
SELECT RTRIM(' Sample ');
結(jié)果:
' Sample'
表格處理
CREATE TABLE
表格是數(shù)據(jù)庫(kù)中儲(chǔ)存資料的基本架構(gòu)。在絕大部份的情況下,數(shù)據(jù)庫(kù)廠商不可能知道您需要如何儲(chǔ)存您的資料,所以通常您會(huì)需要自己在數(shù)據(jù)庫(kù)中建立表格。雖然許多數(shù)據(jù)庫(kù)工具可以讓您在不需用到 SQL 的情況下建立表格,不過(guò)由于表格是一個(gè)最基本的架構(gòu),我們決定包括 CREATE TABLE 的語(yǔ)法在這個(gè)網(wǎng)站中。
在我們跳入 CREATE TABLE 的語(yǔ)法之前,我們最好先對(duì)表格這個(gè)東西有些多一點(diǎn)的了解。表格被分為欄位 (column) 及列位 (row)。每一列代表一筆資料,而每一欄代表一筆資料的一部份。舉例來(lái)說(shuō),如果我們有一個(gè)記載顧客資料的表格,那欄位就有可能包括姓、名、地址、城市、國(guó)家、生日???等等。當(dāng)我們對(duì)表格下定義時(shí),我們需要注明欄位的標(biāo)題,以及那個(gè)欄位的資料種類。
那,資料種類是什么呢?資料可能是以許多不同的形式存在的。它可能是一個(gè)整數(shù) (例如 1),、一個(gè)實(shí)數(shù) (例如 0.55)、一個(gè)字符串 (例如 'sql')、一個(gè)日期/時(shí)間 (例如 '2000-JAN-25 03:22:22')、或甚至是以二進(jìn)法 (binary) 的狀態(tài)存在。當(dāng)我們?cè)趯?duì)一個(gè)表格下定義時(shí),我們需要對(duì)每一個(gè)欄位的資料種類下定義。 (例如 '姓' 這個(gè)欄位的資料種類是 char(50)──代表這是一個(gè) 50 個(gè)字符的字符串)。我們需要注意的一點(diǎn)是不同的數(shù)據(jù)庫(kù)有不同的資料種類,所以在對(duì)表格做出定義之前最好先參考一下數(shù)據(jù)庫(kù)本身的說(shuō)明。
CREATE TABLE 的語(yǔ)法是:
CREATE TABLE "表格名"
("欄位 1" "欄位 1 資料種類",
"欄位 2" "欄位 2 資料種類",
... )
若我們要建立我們上面提過(guò)的顧客表格,我們就鍵入以下的 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
我們可以限制哪一些資料可以存入表格中。這些限制可以在表格初創(chuàng)時(shí)藉由 CREATE TABLE 語(yǔ)句來(lái)指定,或是之后藉由 ALTER TABLE 語(yǔ)句來(lái)指定。
常見的限制有以下幾種:
NOT NULL
UNIQUE
CHECK
主鍵 (Primary Key)
外來(lái)鍵 (Foreign Key)
以下對(duì)這幾種限制分別做個(gè)介紹:
NOT NULL
在沒有做出任何限制的情況下,一個(gè)欄位是允許有 NULL 值得。如果我們不允許一個(gè)欄位含有 NULL 值,我們就需要對(duì)那個(gè)欄位做出 NOT NULL 的指定。
舉例來(lái)說(shuō),在以下的語(yǔ)句中,
CREATE TABLE Customer
(SID integer NOT NULL,
Last_Name varchar (30) NOT NULL,
First_Name varchar(30));
"SID" 和 "Last_Name" 這兩個(gè)欄位是不允許有 NULL 值,而 "First_Name" 這個(gè)欄位是可以有 NULL 值得。
UNIQUE
UNIQUE 限制是保證一個(gè)欄位中的所有資料都是有不一樣的值。
舉例來(lái)說(shuō),在以下的語(yǔ)句中,
CREATE TABLE Customer
(SID integer Unique,
Last_Name varchar (30),
First_Name varchar(30));
"SID" 欄位不能有重復(fù)值存在,而 "Last_Name" 及 "First_Name" 這兩個(gè)欄位則是允許有重復(fù)值存在。
請(qǐng)注意,一個(gè)被指定為主鍵的欄位也一定會(huì)含有 UNIQUE 的特性。相對(duì)來(lái)說(shuō),一個(gè) UNIQUE 的欄位并不一定會(huì)是一個(gè)主鍵。
CHECK
CHECK 限制是保證一個(gè)欄位中的所有資料都是符合某些條件。
舉例來(lái)說(shuō),在以下的語(yǔ)句中,
CREATE TABLE Customer
(SID integer CHECK (SID > 0),
Last_Name varchar (30),
First_Name varchar(30));
"SID" 攔只能包含大于 0 的整數(shù)。
請(qǐng)注意,CHECK 限制目前尚未被執(zhí)行于 MySQL 數(shù)據(jù)庫(kù)上。
主鍵 and 外來(lái)鍵 將于下兩頁(yè)中討論。
主鍵
主鍵 (Primary Key) 中的每一筆資料都是表格中的唯一值。換言之,它是用來(lái)獨(dú)一無(wú)二地確認(rèn)一個(gè)表格中的每一行資料。主鍵可以是原本資料內(nèi)的一個(gè)欄位,或是一個(gè)人造欄位 (與原本資料沒有關(guān)系的欄位)。主鍵可以包含一或多個(gè)欄位。當(dāng)主鍵包含多個(gè)欄位時(shí),稱為組合鍵 (Composite Key)。
主鍵可以在建置新表格時(shí)設(shè)定 (運(yùn)用 CREATE TABLE 語(yǔ)句),或是以改變現(xiàn)有的表格架構(gòu)方式設(shè)定 (運(yùn)用 ALTER TABLE)。
以下舉幾個(gè)在建置新表格時(shí)設(shè)定主鍵的方式:
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));
以下則是以改變現(xiàn)有表格架構(gòu)來(lái)設(shè)定主鍵的方式:
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);
請(qǐng)注意,在用ALTER TABLE語(yǔ)句來(lái)添加主鍵之前,我們需要確認(rèn)被用來(lái)當(dāng)做主鍵的欄位是設(shè)定為 『NOT NULL』 ;也就是說(shuō),那個(gè)欄位一定不能沒有資料。
外來(lái)鍵
外來(lái)鍵是一個(gè)(或數(shù)個(gè))指向另外一個(gè)表格主鍵的欄位。外來(lái)鍵的目的是確定資料的參考完整性(referential integrity)。換言之,只有被準(zhǔn)許的資料值才會(huì)被存入數(shù)據(jù)庫(kù)內(nèi)。
舉例來(lái)說(shuō),假設(shè)我們有兩個(gè)表格:一個(gè) CUSTOMER 表格,里面記錄了所有顧客的資料;另一個(gè) ORDERS 表格,里面記錄了所有顧客訂購(gòu)的資料。在這里的一個(gè)限制,就是所有的訂購(gòu)資料中的顧客,都一定是要跟在 CUSTOMER 表格中存在。在這里,我們就會(huì)在 ORDERS 表格中設(shè)定一個(gè)外來(lái)鍵,而這個(gè)外來(lái)鍵是指向 CUSTOMER 表格中的主鍵。這樣一來(lái),我們就可以確定所有在 ORDERS 表格中的顧客都存在 CUSTOMER 表格中。換句話說(shuō),ORDERS表格之中,不能有任何顧客是不存在于 CUSTOMER 表格中的資料。
這兩個(gè)表格的結(jié)構(gòu)將會(huì)是如下:
CUSTOMER 表格
欄位名
性質(zhì)
SID
主鍵
Last_Name
First_Name
ORDERS 表格
欄位名
性質(zhì)
Order_ID
主鍵
Order_Date
Customer_SID
外來(lái)鍵
Amount
在以上的例子中,ORDERS 表格中的 customer_SID 欄位是一個(gè)指向 CUSTOMERS 表格中 SID 欄位的外來(lái)鍵。
以下列出幾個(gè)在建置 ORDERS 表格時(shí)指定外來(lái)鍵的方式:
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);
以下的例子則是藉著改變表格架構(gòu)來(lái)指定外來(lái)鍵。這里假設(shè) ORDERS 表格已經(jīng)被建置,而外來(lái)鍵尚未被指定:
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) 可以被當(dāng)作是虛擬表格。它跟表格的不同是,表格中有實(shí)際儲(chǔ)存資料,而視觀表是建立在表格之上的一個(gè)架構(gòu),它本身并不實(shí)際儲(chǔ)存資料。
建立一個(gè)視觀表的語(yǔ)法如下:
CREATE VIEW "VIEW_NAME" AS "SQL 語(yǔ)句"
"SQL 語(yǔ)句" 可以是任何一個(gè)我們?cè)谶@個(gè)教材中有提到的 SQL。
來(lái)看一個(gè)例子。假設(shè)我們有以下的表格:
TABLE Customer
(First_Name char(50),
Last_Name char(50),
Address char(50),
City char(50),
Country char(25),
Birth_Date date)
若要在這個(gè)表格上建立一個(gè)包括 First_Name, Last_Name, 和 Country 這三個(gè)欄位的視觀表,我們就打入,
CREATE VIEW V_Customer
AS SELECT First_Name, Last_Name, Country
FROM Customer
現(xiàn)在,我們就有一個(gè)叫做 V_Customer 的視觀表:
View V_Customer
(First_Name char(50),
Last_Name char(50),
Country char(25))
我們也可以用視觀表來(lái)連接兩個(gè)表格。在這個(gè)情況下,使用者就可以直接由一個(gè)視觀表中找出她要的信息,而不需要由兩個(gè)不同的表格中去做一次連接的動(dòng)作。假設(shè)有以下的兩個(gè)表格: 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
我們就可以用以下的指令來(lái)建一個(gè)包括每個(gè)地區(qū) (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
這就給我們有一個(gè)名為 V_REGION_SALES 的視觀表。這個(gè)視觀表包含不同地區(qū)的銷售哦。如果我們要從這個(gè)視觀表中獲取資料,我們就打入,
SELECT * FROM V_REGION_SALES
結(jié)果:
REGION SALES
East $700
West $2050
CREATE INDEX
索引 (Index) 可以幫助我們從表格中快速地找到需要的資料。舉例來(lái)說(shuō),假設(shè)我們要在一本園藝書中找如何種植青椒的訊息。若這本書沒有索引的話,那我們是必須要從頭開始讀,直到我們找到有關(guān)種直青椒的地方為止。若這本書有索引的話,我們就可以先去索引找出種植青椒的信息是在哪一頁(yè),然后直接到那一頁(yè)去閱讀。很明顯地,運(yùn)用索引是一種有效且省時(shí)的方式。
從數(shù)據(jù)庫(kù)表格中尋找資料也是同樣的原理。如果一個(gè)表格沒有索引的話,數(shù)據(jù)庫(kù)系統(tǒng)就需要將整個(gè)表格的資料讀出 (這個(gè)過(guò)程叫做'table scan')。若有適當(dāng)?shù)乃饕嬖?,?shù)據(jù)庫(kù)系統(tǒng)就可以先由這個(gè)索引去找出需要的資料是在表格的什么地方,然后直接去那些地方抓資料。這樣子速度就快多了。
因此,在表格上建立索引是一件有利于系統(tǒng)效率的事。一個(gè)索引可以涵蓋一或多個(gè)欄位。建立索引的語(yǔ)法如下:
CREATE INDEX "INDEX_NAME" ON "TABLE_NAME" (COLUMN_NAME)
現(xiàn)在假設(shè)我們有以下這個(gè)表格,
TABLE Customer
(First_Name char(50),
Last_Name char(50),
Address char(50),
City char(50),
Country char(25),
Birth_Date date)
若我們要在 Last_Name 這個(gè)欄位上建一個(gè)索引,我們就打入以下的指令,
CREATE INDEX IDX_CUSTOMER_LAST_NAME
on CUSTOMER (Last_Name)
我們要在 City 及 Country 這兩個(gè)欄位上建一個(gè)索引,我們就打入以下的指令,
CREATE INDEX IDX_CUSTOMER_LOCATION
on CUSTOMER (City, Country)
索引的命名并沒有一個(gè)固定的方式。通常會(huì)用的方式是在名稱前加一個(gè)字首,例如 "IDX_" ,來(lái)避免與數(shù)據(jù)庫(kù)中的其他物件混淆。另外,在索引名之內(nèi)包括表格名及欄位名也是一個(gè)好的方式。
請(qǐng)讀者注意,每個(gè)數(shù)據(jù)庫(kù)會(huì)有它本身的 CREATE INDEX 語(yǔ)法,而不同數(shù)據(jù)庫(kù)的語(yǔ)法會(huì)有不同。因此,在下指令前,請(qǐng)先由數(shù)據(jù)庫(kù)使用手冊(cè)中確認(rèn)正確的語(yǔ)法。
ALTER TABLE
在表格被建立在數(shù)據(jù)庫(kù)中后,我們常常會(huì)發(fā)現(xiàn),這個(gè)表格的結(jié)構(gòu)需要有所改變。常見的改變?nèi)缦拢?div style="height:15px;">
加一個(gè)欄位
刪去一個(gè)欄位
改變欄位名稱
改變欄位的資料種類
以上列出的改變并不是所有可能的改變。ALTER TABLE 也可以被用來(lái)作其他的改變,例如改變主鍵定義。
ALTER TABLE 的語(yǔ)法如下:
ALTER TABLE "table_name"
[改變方式]
[改變方式] 的詳細(xì)寫法會(huì)依我們想要達(dá)到的目標(biāo)而有所不同。再以上列出的改變中,[改變方式] 如下:
加一個(gè)欄位: ADD "欄位 1" "欄位 1 資料種類"
刪去一個(gè)欄位: DROP "欄位 1"
改變欄位名稱: CHANGE "原本欄位名" "新欄位名" "新欄位名資料種類"
改變欄位的資料種類: MODIFY "欄位 1" "新資料種類"
以下我們用在CREATE TABLE 一頁(yè)建出的 customer 表格來(lái)當(dāng)作例子:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Address
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
第一,我們要加入一個(gè)叫做 "gender" 的欄位。這可以用以下的指令達(dá)成:
ALTER table customer add Gender char(1)
這個(gè)指令執(zhí)行后的表格架構(gòu)是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Address
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
接下來(lái),我們要把 "Address" 欄位改名為 "Addr"。這可以用以下的指令達(dá)成:
ALTER table customer change Address Addr char(50)
這個(gè)指令執(zhí)行后的表格架構(gòu)是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(50)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
再來(lái),我們要將 "Addr" 欄位的資料種類改為 char(30)。這可以用以下的指令達(dá)成:
ALTER table customer modify Addr char(30)
這個(gè)指令執(zhí)行后的表格架構(gòu)是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(30)
City
char(50)
Country
char(25)
Birth_Date
date
Gender
char(1)
最后,我們要?jiǎng)h除 "Gender" 欄位。這可以用以下的指令達(dá)成:
ALTER table customer drop Gender
這個(gè)指令執(zhí)行后的表格架構(gòu)是:
customer 表格
欄位名稱
資料種類
First_Name
char(50)
Last_Name
char(50)
Addr
char(30)
City
char(50)
Country
char(25)
Birth_Date
date
DROP TABLE
有時(shí)候我們會(huì)決定我們需要從數(shù)據(jù)庫(kù)中清除一個(gè)表格。事實(shí)上,如果我們不能這樣做的話,那將會(huì)是一個(gè)很大的問題,因?yàn)閿?shù)據(jù)庫(kù)管理師 (Database Administrator -- DBA) 勢(shì)必?zé)o法對(duì)數(shù)據(jù)庫(kù)做有效率的管理。還好,SQL 有提供一個(gè) DROP TABLE 的語(yǔ)法來(lái)讓我們清除表格。 DROP TABLE 的語(yǔ)法是:
DROP TABLE "表格名"
我們?nèi)绻宄谏弦豁?yè)中建立的顧客表格,我們就鍵入:
DROP TABLE customer.
TRUNCATE TABLE
有時(shí)候我們會(huì)需要清除一個(gè)表格中的所有資料。要達(dá)到者個(gè)目的,一種方式是我們?cè)?上一頁(yè)看到 的 DROP TABLE 指令。不過(guò)這樣整個(gè)表格就消失,而無(wú)法再被用了。另一種方式就是運(yùn)用 TRUNCATE TABLE 的指令。在這個(gè)指令之下,表格中的資料會(huì)完全消失,可是表格本身會(huì)繼續(xù)存在。 TRUNCATE TABLE 的語(yǔ)法為下:
TRUNCATE TABLE "表格名"
所以,我們?nèi)绻宄?SQL Create Table 那一頁(yè)建立的顧客表格之內(nèi)的資料,我們就鍵入:
TRUNCATE TABLE customer.
INSERT INTO
到目前為止,我們學(xué)到了將如何把資料由表格中取出。但是這些資料是如果進(jìn)入這些表格的呢?這就是這一頁(yè) (INSERT INTO) 和下一頁(yè) (UPDATE) 要討論的。
基本上,我們有兩種作法可以將資料輸入表格中內(nèi)。一種是一次輸入一筆,另一種是一次輸入好幾筆。我們先來(lái)看一次輸入一筆的方式。
依照慣例,我們先介紹語(yǔ)法。一次輸入一筆資料的語(yǔ)法如下:
INSERT INTO "表格名" ("欄位1", "欄位2", ...)
VALUES ("值1", "值2", ...)
假設(shè)我們有一個(gè)架構(gòu)如下的表格:
Store_Information 表格
Column Name
Data Type
store_name
char(50)
Sales
float
Date
datetime
而我們要加以下的這一筆資料進(jìn)去這個(gè)表格:在 January 10, 1999,Los Angeles 店有 $900 的營(yíng)業(yè)額。我們就打入以下的 SQL 語(yǔ)句:
INSERT INTO Store_Information (store_name, Sales, Date)
VALUES ('Los Angeles', 900, 'Jan-10-1999')
第二種 INSERT INTO 能夠讓我們一次輸入多筆的資料。跟上面剛的例子不同的是,現(xiàn)在我們要用 SELECT 指令來(lái)指明要輸入表格的資料。如果您想說(shuō),這是不是說(shuō)資料是從另一個(gè)表格來(lái)的,那您就想對(duì)了。一次輸入多筆的資料的語(yǔ)法是:
INSERT INTO "表格1" ("欄位1", "欄位2", ...)
SELECT "欄位3", "欄位4", ...
FROM "表格2"
以上的語(yǔ)法是最基本的。這整句 SQL 也可以含有 WHERE、 GROUP BY、及 HAVING 等子句,以及表格連接及別名等等。
舉例來(lái)說(shuō),若我們想要將 1998 年的營(yíng)業(yè)額資料放入 Store_Information 表格,而我們知道資料的來(lái)源是可以由 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 中的函數(shù)來(lái)由日期中找出年。不同的數(shù)據(jù)庫(kù)會(huì)有不同的語(yǔ)法。舉個(gè)例來(lái)說(shuō),在 Oracle 上,您將會(huì)使用 WHERE to_char(date,'yyyy')=1998。
UPDATE
我們有時(shí)候可能會(huì)需要修改表格中的資料。在這個(gè)時(shí)候,我們就需要用到 UPDATE 指令。這個(gè)指令的語(yǔ)法是:
UPDATE "表格名"
SET "欄位1" = [新值]
WHERE {條件}
最容易了解這個(gè)語(yǔ)法的方式是透過(guò)一個(gè)例子。假設(shè)我們有以下的表格:
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
我們發(fā)現(xiàn)說(shuō) Los Angeles 在 01/08/1999 的營(yíng)業(yè)額實(shí)際上是 $500,而不是表格中所儲(chǔ)存的 $300,因此我們用以下的 SQL 來(lái)修改那一筆資料:
UPDATE Store_Information
SET Sales = 500
WHERE store_name = "Los Angeles"
AND Date = "Jan-08-1999"
現(xiàn)在表格的內(nèi)容變成:
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
在這個(gè)例子中,只有一筆資料符合 WHERE 子句中的條件。如果有多筆資料符合條件的話,每一筆符合條件的資料都會(huì)被修改的。
我們也可以同時(shí)修改好幾個(gè)欄位。這語(yǔ)法如下:
UPDATE "表格"
SET "欄位1" = [值1], "欄位2" = [值2]
WHERE {條件}
DELETE FROM
在某些情況下,我們會(huì)需要直接由數(shù)據(jù)庫(kù)中去除一些資料。這可以藉由 DELETE FROM 指令來(lái)達(dá)成。它的語(yǔ)法是:
DELETE FROM "表格名"
WHERE {條件}
以下我們用個(gè)實(shí)例說(shuō)明。假設(shè)我們有以下這個(gè)表格:
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
而我們需要將有關(guān) Los Angeles 的資料全部去除。在這里我們可以用以下的 SQL 來(lái)達(dá)到這個(gè)目的:
DELETE FROM Store_Information
WHERE store_name = "Los Angeles"
現(xiàn)在表格的內(nèi)容變成:
Store_Information 表格
store_name
Sales
Date
San Diego
$250
Jan-07-1999
Boston
$700
Jan-08-1999
進(jìn)階SQL
在這一部分,我們將介紹以下的 SQL 概念及關(guān)鍵字:
SQL UNIONSQL UNION ALLSQL INTERSECTSQL MINUSSQL SubquerySQL EXISTSSQL CASE我們并介紹如何用 SQL 來(lái)做出以下的運(yùn)算:
排名 (Rank)中位數(shù) (Median)累積總計(jì) (Running Total)總合百分比 (Percent to Total)累積總合百分比 (Cumulative Percent to Total)UNION
UNION 指令的目的是將兩個(gè) SQL 語(yǔ)句的結(jié)果合并起來(lái)。從這個(gè)角度來(lái)看, UNION 跟 JOIN 有些許類似,因?yàn)檫@兩個(gè)指令都可以由多個(gè)表格中擷取資料。 UNION 的一個(gè)限制是兩個(gè) SQL 語(yǔ)句所產(chǎn)生的欄位需要是同樣的資料種類。另外,當(dāng)我們用 UNION 這個(gè)指令時(shí),我們只會(huì)看到不同的資料值 (類似 SELECT DISTINCT)。
UNION 的語(yǔ)法如下:
[SQL 語(yǔ)句 1]
UNION
[SQL 語(yǔ)句 2]
假設(shè)我們有以下的兩個(gè)表格,
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
而我們要找出來(lái)所有有營(yíng)業(yè)額 (sales) 的日子。要達(dá)到這個(gè)目的,我們用以下的 SQL 語(yǔ)句:
SELECT Date FROM Store_Information
UNION
SELECT Date FROM Internet_Sales
結(jié)果:
Date
Jan-05-1999
Jan-07-1999
Jan-08-1999
Jan-10-1999
Jan-11-1999
Jan-12-1999
有一點(diǎn)值得注意的是,如果我們?cè)谌魏我粋€(gè) SQL 語(yǔ)句 (或是兩句都一起) 用 "SELECT DISTINCT Date" 的話,那我們會(huì)得到完全一樣的結(jié)果。
UNION ALL
UNION ALL 這個(gè)指令的目的也是要將兩個(gè) SQL 語(yǔ)句的結(jié)果合并在一起。 UNION ALL 和 UNION 不同之處在于 UNION ALL 會(huì)將每一筆符合條件的資料都列出來(lái),無(wú)論資料值有無(wú)重復(fù)。
UNION ALL 的語(yǔ)法如下:
[SQL 語(yǔ)句 1]
UNION ALL
[SQL 語(yǔ)句 2]
我們用和上一頁(yè)同樣的例子來(lái)顯示出 UNION ALL 和 UNION 的不同。同樣假設(shè)我們有以下兩個(gè)表格,
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
而我們要找出有店面營(yíng)業(yè)額以及網(wǎng)絡(luò)營(yíng)業(yè)額的日子。要達(dá)到這個(gè)目的,我們用以下的 SQL 語(yǔ)句:
SELECT Date FROM Store_Information
UNION ALL
SELECT Date FROM Internet_Sales
結(jié)果:
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 也是對(duì)兩個(gè) SQL 語(yǔ)句所產(chǎn)生的結(jié)果做處理的。不同的地方是, UNION 基本上是一個(gè) OR (如果這個(gè)值存在于第一句或是第二句,它就會(huì)被選出),而 INTERSECT 則比較像 AND (這個(gè)值要存在于第一句和第二句才會(huì)被選出)。 UNION 是聯(lián)集,而 INTERSECT 是交集。
INTERSECT 的語(yǔ)法如下:
[SQL 語(yǔ)句 1]
INTERSECT
[SQL 語(yǔ)句 2]
假設(shè)我們有以下的兩個(gè)表格,
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
而我們要找出哪幾天有店面交易和網(wǎng)絡(luò)交易。要達(dá)到這個(gè)目的,我們用以下的 SQL 語(yǔ)句:
SELECT Date FROM Store_Information
INTERSECT
SELECT Date FROM Internet_Sales
結(jié)果:
Date
Jan-07-1999
請(qǐng)注意,在 INTERSECT 指令下,不同的值只會(huì)被列出一次。
MINUS
MINUS 指令是運(yùn)用在兩個(gè) SQL 語(yǔ)句上。它先找出第一個(gè) SQL 語(yǔ)句所產(chǎn)生的結(jié)果,然后看這些結(jié)果有沒有在第二個(gè) SQL 語(yǔ)句的結(jié)果中。如果有的話,那這一筆資料就被去除,而不會(huì)在最后的結(jié)果中出現(xiàn)。如果第二個(gè) SQL 語(yǔ)句所產(chǎn)生的結(jié)果并沒有存在于第一個(gè) SQL 語(yǔ)句所產(chǎn)生的結(jié)果內(nèi),那這筆資料就被拋棄。
MINUS 的語(yǔ)法如下:
[SQL 語(yǔ)句 1]
MINUS
[SQL 語(yǔ)句 2]
我們繼續(xù)使用一樣的例子:
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
而我們要知道有哪幾天是有店面營(yíng)業(yè)額而沒有網(wǎng)絡(luò)營(yíng)業(yè)額的。要達(dá)到這個(gè)目的,我們用以下的 SQL 語(yǔ)句:
SELECT Date FROM Store_Information
MINUS
SELECT Date FROM Internet_Sales
結(jié)果:
Date
Jan-05-1999
Jan-08-1999
"Jan-05-1999", "Jan-07-1999", and "Jan-08-1999" 是 "SELECT Date FROM Store_Information" 所產(chǎn)生的結(jié)果。在這里面, "Jan-07-1999" 是存在于 "SELECT Date FROM Internet_Sales" 所產(chǎn)生的結(jié)果中。因此 "Jan-07-1999" 并不在最后的結(jié)果中。
請(qǐng)注意,在 MINUS 指令下,不同的值只會(huì)被列出一次。
子查詢
我們可以在一個(gè) SQL 語(yǔ)句中放入另一個(gè) SQL 語(yǔ)句。當(dāng)我們?cè)?WHERE 子句或 HAVING 子句中插入另一個(gè) SQL 語(yǔ)句時(shí),我們就有一個(gè)子查詢 (subquery) 的架構(gòu)。 子查詢的作用是什么呢?第一,它可以被用來(lái)連接表格。另外,有的時(shí)候子查詢是唯一能夠連接兩個(gè)表格的方式。
子查詢的語(yǔ)法如下:
SELECT "欄位1"
FROM "表格"
WHERE "欄位2" [比較運(yùn)算素]
(SELECT "欄位1"
FROM "表格"
WHERE [條件])
[比較運(yùn)算素] 可以是相等的運(yùn)算素,例如 =, >, <, >=, <=. 這也可以是一個(gè)對(duì)文字的運(yùn)算素,例如 "LIKE"。綠色的部分代表外查詢,紅色的部分代表內(nèi)查詢。
我們就用剛剛在闡述 SQL 連接時(shí)用過(guò)的例子:
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
我們要運(yùn)用 subquery 來(lái)找出所有在西部的店的營(yíng)業(yè)額。我們可以用下面的 SQL 來(lái)達(dá)到我們的目的:
SELECT SUM(Sales) FROM Store_Information
WHERE Store_name IN
(SELECT store_name FROM Geography
WHERE region_name = 'West')
結(jié)果:
SUM(Sales)
2050
在這個(gè)例子中,我們并沒有直接將兩個(gè)表格連接起來(lái),然后由此直接算出每一間西區(qū)店面的營(yíng)業(yè)額。我們做的是先找出哪些店是在西區(qū)的,然后再算出這些店的營(yíng)業(yè)額總共是多少。
在以上的例子,內(nèi)部查詢本身與外部查詢沒有關(guān)系。這一類的子查詢稱為『簡(jiǎn)單子查詢』 (Simple Subquery)。如果內(nèi)部查詢是要利用到外部查詢提到的表格中的欄位,那這個(gè)字查詢就被稱為『相關(guān)子查詢』 (Correlated Subquery)。以下是一個(gè)相關(guān)子查詢的例子:
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
在上一頁(yè)中,我們用 IN 來(lái)連接內(nèi)查詢和外查詢。另外有數(shù)個(gè)方式,例如 >, <, 及 =,都可以用來(lái)連接內(nèi)查詢和外查詢。 EXISTS 也是其中一種方式。這一頁(yè)我們將討論 EXISTS 的用法。
基本上, EXISTS 是用來(lái)測(cè)試內(nèi)查詢有沒有產(chǎn)生任何結(jié)果。如果有的話,系統(tǒng)就會(huì)執(zhí)行外查詢中的 SQL。若是沒有的話,那整個(gè) SQL 語(yǔ)句就不會(huì)產(chǎn)生任何結(jié)果。
EXISTS 的語(yǔ)法是:
SELECT "欄位1"
FROM "表格1"
WHERE EXISTS
(SELECT *
FROM "表格2"
WHERE [條件])
在內(nèi)查詢中,我們并不一定要用 * 來(lái)選出所有的欄位。我們也可以選擇表格2中的任何欄位。這兩種做法最后的結(jié)果是一樣的。
來(lái)看一個(gè)例子。假設(shè)我們有以下的兩個(gè)表格:
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')
我們會(huì)得到以下的答案:
SUM(Sales)
2750
乍看之下,這個(gè)答案似乎不太正確,因?yàn)閮?nèi)查詢有包含一個(gè) [region_name = 'West'] 的條件,可是最后的答案并沒有包含這個(gè)條件。實(shí)際上,這并沒有問題。在這個(gè)例子中,內(nèi)查詢產(chǎn)生了超過(guò)一筆的資料,所以 EXISTS 的條件成立,所以外查詢被執(zhí)行。而外查詢本身并沒有包含 [region_name = 'West'] 這個(gè)條件。
CASE
CASE 是 SQL 用來(lái)做為 if-then-else 之類邏輯的關(guān)鍵字。 CASE 的語(yǔ)法如下:
SELECT CASE ("欄位名")
WHEN "條件1" THEN "結(jié)果1"
WHEN "條件2" THEN "結(jié)果2"
...
[ELSE "結(jié)果N"]
END
FROM "表格名"
"條件" 可以是一個(gè)數(shù)值或是公式。 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 數(shù)值乘以2,以及將 'San Diego' 的 Sales 數(shù)值乘以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 那個(gè)欄位的欄位名。
結(jié)果:
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
算排名
列出每一行的排名是一個(gè)常見的需求,可惜 SQL 并沒有一個(gè)很直接的方式達(dá)到這個(gè)需求。要以 SQL 列出排名,基本的概念是要做一個(gè)表格自我連結(jié) (self join),將結(jié)果依序列出,然后算出每一行之前 (包含那一行本身) 有多少行數(shù)。這樣講讀者聽得可能有點(diǎn)困惑,所以最好的方式是用一個(gè)實(shí)例來(lái)介紹。假設(shè)我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要找出每一行的排名,我們就打入以下的 SQL 語(yǔ)句:
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;
結(jié)果:
Name Sales Sales_Rank
Greg 50 1
Sophia 40 2
Stella 20 3
Jeff 20 3
Jennifer 15 5
John 10 6
我們先來(lái)看 WHERE 子句。在字句的第一部分 (a1.Sales <= a2.Sales),我們算出有多少筆資料 Sales 欄位的值是比自己本身的值小或是相等。如果在 Sales 欄位中沒有同樣大小的資料,那這部分的 WHERE 子句本身就可以產(chǎn)生出正確的排名。
子句的第二部分,(a1.Sales=a2.Sales and a1.Name = a2.Name),則是讓我們?cè)?Sales 欄位中有同樣大小的資料時(shí) (像 Stella 及 Jeff 這兩筆資料),仍然能夠產(chǎn)生正確的排名。
算中位數(shù)
要算出中位數(shù),我們必須要能夠達(dá)成以下幾個(gè)目標(biāo):
將資料依序排出,并找出每一行資料的排名。
找出『中間』的排名為何。舉例來(lái)說(shuō),如果總共有 9 筆資料,那中間排名就是 5 (有 4 筆資料比第 5 筆資料大,有 4 筆資料比第 5 筆資料小)。
找出中間排名資料的值。
來(lái)看看以下的例子。假設(shè)我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要找出中位數(shù),我們就鍵入:
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);
結(jié)果:
Median
20
讀者將會(huì)發(fā)現(xiàn),第 2 行到第 6 行是跟產(chǎn)生 排名 的語(yǔ)句完全一樣。第 7 行則是算出中間的排名。DIV 是在 MySQL 中算出商的方式。在不同的數(shù)據(jù)庫(kù)中會(huì)有不同的方式求商。第 1 行則是列出排名中間的資料值。
算累積總計(jì)
算出累積總計(jì)是一個(gè)常見的需求,可惜以 SQL 并沒有一個(gè)很直接的方式達(dá)到這個(gè)需求。要以 SQL 算出累積總計(jì),基本上的概念與列出排名類似:第一是先做個(gè)表格自我連結(jié) (self join),然后將結(jié)果依序列出。在做列出排名時(shí),我們算出每一行之前 (包含那一行本身) 有多少行數(shù);而在做累積總計(jì)時(shí),我們則是算出每一行之前 (包含那一行本身) 的總合。
來(lái)看看以下的例子。假設(shè)我們有以下的表格:
Total_Sales 表格
Name
Sales
John
10
Jennifer
15
Stella
20
Sophia
40
Greg
50
Jeff
20
要算出累積總計(jì),我們就鍵入:
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;
結(jié)果:
Name Sales Running_Total
Greg 50 50
Sophia 40 90
Stella 20 110
Jeff 20 130
Jennifer 15 145
John 10 155
在以上的 SQL 語(yǔ)句中, WHERE 子句和 ORDER BY 子句讓我們能夠在有重復(fù)值時(shí)能夠算出正確的累積總計(jì)。
算總合百分比
要用 SQL 算出總合百分比,我們需要用到算排名和累積總計(jì)的概念,以及運(yùn)用子查詢的做法。在這里,我們把子查詢放在外部查詢的 SELECT 子句中。讓我們來(lái)看以下的例子:
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;
結(jié)果:
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" 這一段子查詢是用來(lái)算出總合??偤纤愠龊螅覀兙湍軌?qū)⒚恳恍幸灰怀钥偤蟻?lái)求出每一行的總合百分比。
算累積總合百分比
要用 SQL 累積總合百分比算出,我們運(yùn)用類似總合百分比的概念。兩者的不同處在于在這個(gè)情況下,我們要算出到目前為止的累積總合是所有總合的百分之幾,而不是光看每一筆資料是所有總合的百分之幾。讓我們來(lái)看看以下的例子:
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;
結(jié)果:
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" 這一段子查詢是用來(lái)算出總合。我們接下來(lái)用累積總計(jì) "SUM(a2.Sales)" 除以總合來(lái)求出每一行的累積總合百分比。
SQL語(yǔ)法
Select
SELECT "欄位" FROM "表格名"
Distinct
SELECT DISTINCT "欄位"
FROM "表格名"
Where
SELECT "欄位"
FROM "表格名"
WHERE "condition"
And/Or
SELECT "欄位"
FROM "表格名"
WHERE "簡(jiǎn)單條件"
{[AND|OR] "簡(jiǎn)單條件"}+
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 (函數(shù)條件)
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 {條件}
來(lái)自:http://www.1keydata.com/tw/sql/sql.html