SQL 裡面最常用的命令是 SELECT 語句,用於檢索資料。文法是:
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
* | expression [ AS output_name ] [, ...]
[ INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY expression [, ...] ]
[ HAVING condition [, ...] ]
[ { UNION | INTERSECT | EXCEPT [ ALL ] } select ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]
[ FOR UPDATE [ OF class_name [, ...] ] ]
[ LIMIT { count | ALL } [ { OFFSET | , } start ]]
現在我們將通過不同的例子示範 SELECT 語句複雜的文法。用於這些例子的表在 供應商和組件資料庫 裡定義。
1.4.1.1. 簡單的 Select
這裡是一些使用 SELECT 語句的簡單例子:
Example 1-4. 帶有條件的簡單查詢
要從表 PART 裡面把欄位 PRICE 大於 10 的所有記錄找出來, 我們寫出下面查詢:
SELECT * FROM PART
WHERE PRICE > 10;
然後得到表:
PNO | PNAME | PRICE
-----+---------+--------
3 | Bolt | 15
4 | Cam | 25
在 SELECT語句裡使用 "*" 將檢索出表中的所有屬性。 如果我們只希望從表 PART 中檢索出屬性 PNAME 和 PRICE, 我們使用下面的語句:
SELECT PNAME, PRICE
FROM PART
WHERE PRICE > 10;
這回我們的結果是:
PNAME | PRICE
--------+--------
Bolt | 15
Cam | 25
請注意 SQL 的 SELECT 語句對應關係演算裡面的 "projection" (映射),而不是 "selection"(選擇)(參閱 關係演算 擷取詳細資料)。
WHERE 子句裡的條件也可以用關鍵字 OR,AND,和 NOT 邏輯地串連起來:
SELECT PNAME, PRICE
FROM PART
WHERE PNAME = 'Bolt' AND
(PRICE = 0 OR PRICE <= 15);
這樣將產生下面的結果:
PNAME | PRICE
--------+--------
Bolt | 15
目標列表和 WHERE 子句裡可以使用算術操作。例如, 如果我們想知道如果我們買兩個組件的話要多少錢, 我們可以用下面的查詢:
SELECT PNAME, PRICE * 2 AS DOUBLE
FROM PART
WHERE PRICE * 2 < 50;
這樣我們得到:
PNAME | DOUBLE
--------+---------
Screw | 20
Nut | 16
Bolt | 30
請注意在關鍵字 AS 後面的 DOUBLE 是第二個列的新名字。 這個技巧可以用於目標列表裡的每個元素, 給它們賦予一個在結果列中顯示的新的標題。 這個新的標題通常稱為別名。這個別名不能在該查詢的其他地方使用。
1.4.1.2. Joins(串連)
下面的例子顯示了 SQL 裡是如何?串連的。
要在共同的屬性上串連三個表 SUPPLIER,PART 和 SELLS, 我們通常使用下面的語句:
SELECT S.SNAME, P.PNAME
FROM SUPPLIER S, PART P, SELLS SE
WHERE S.SNO = SE.SNO AND
P.PNO = SE.PNO;
而我們得到的結果是:
SNAME | PNAME
-------+-------
Smith | Screw
Smith | Nut
Jones | Cam
Adams | Screw
Adams | Bolt
Blake | Nut
Blake | Bolt
Blake | Cam
在 FROM 子句裡,我們為每個關係使用了一個別名, 因為在這些關係間有著公用的命名屬性(SNO 和 PNO)。 現在我們可以區分不同表的公用命名屬性, 只需要簡單的用每個關係的別名加上個點做首碼就行了。 聯合是用與 一個內部聯結
裡顯示的同樣的方法計算的。首先算出笛卡兒積 SUPPLIER × PART × SELLS 。然後選出那些滿足 WHERE
子句裡給出的條件的記錄 (也就是說,公用命名屬性的值必須相等)。 最後我們映射出除 S.SNAME 和 P.PNAME 外的所有屬性。
另外一個進行串連的方法是使用下面這樣的 SQL JOIN 文法:
select sname, pname from supplier
JOIN sells USING (sno)
JOIN part USING (pno);
giving again:
sname | pname
-------+-------
Smith | Screw
Adams | Screw
Smith | Nut
Blake | Nut
Adams | Bolt
Blake | Bolt
Jones | Cam
Blake | Cam
(8 rows)
一
個用 JOIN 文法建立的串連表,是一個出現在 FROM 子句裡的, 在任何 WHERE,GROUP BY 或 HAVING
子句之前的表引用清單項目. 其它表引用,包括表名字或者其它 JOIN 子句,如果用逗號分隔的話, 可以包含在 FROM 子句裡.
串連產生的表邏輯上和任何其它在 FROM 子句裡列出的表都一樣.
SQL JOIN 有兩種主要類型,CROSS JOIN (無條件串連) 和條件串連.條件串連還可以根據聲明的 串連條件(ON,USING,或 NATURAL)和它 應用的方式(INNER 或 OUTER 串連)進一步細分.
連線類型
-
CROSS JOIN
-
{ T1 } CROSS JOIN { T2 }
一
個交叉串連(cross join)接收兩個分別有 N 行和 M 行 的表 T1 和 T2,然後返回一個包含交叉乘積 NxM 條記錄的 串連表.
對於 T1 的每行 R1,T2 的每行 R2 都與 R1 串連產生 串連的表行 JR,JR 包含所有 R1 和 R2 的欄位. CROSS
JOIN 實際上就是一個 INNER JOIN ON TRUE.
-
條件 JOIN
-
{ T1 } [ NATURAL ] [ INNER | { LEFT | RIGHT | FULL } [ OUTER ] ] JOIN { T2 } { ON search condition | USING ( join column list ) }
一個條件 JOIN 必須通過提供一個(並且只能有一個) NATURAL,ON,或者 USING 這樣的關鍵字來聲明它的 串連條件. ON 子句 接受一個 search condition,
它與一個 WHERE 子句相同.USING 子句接受一個用逗號分隔的 欄位名列表,串連表中必須都有這些欄位,
並且用那些欄位串連這些表,產生的串連表包含每個共有欄位 和兩個表的所有其它欄位. NATURAL 是 USING
子句的縮寫,它列出兩個表中所有公用 的欄位名字.使用 USING 和 NATURAL 的副作用是 每個串連的欄位都只有一份拷貝出現在結果表中
(與前面定義的關係演算的 JOIN 相比較).
-
[ INNER ] JOIN
-
對於 T1 的每行 R1,串連成的表在 T2 裡都有一行滿 足與 R1 一起的串連條件.
對於所有 JOIN 而言,INNER 和 OUTER 都是可選的.INNER 是預設. LEFT,RIGHT,和 FULL 只用於 OUTER JOIN.
-
LEFT [ OUTER ] JOIN
-
首先,執行一次 INNER JOIN. 然後,如果 T1 裡有一行對任何 T2 的行都不滿足 串連條件,那麼返回一個串連行,該行的 T2 的欄位 為 null.
小技巧: 串連成的表無條件地包含 T1 裡的所有行.
-
RIGHT [ OUTER ] JOIN
-
首先,執行一次 INNER JOIN. 然後,如果 T2 裡有一行對任何 T1 的行都不滿足 串連條件,那麼返回一個串連行,該行的 T1 的欄位 為 null.
小技巧: 串連成的表無條件地包含 T2 裡的所有行.
-
FULL [ OUTER ] JOIN
-
首
先,執行一次 INNER JOIN. 然後,如果 T1 裡有一行對任何 T2 的行都不滿足 串連條件,那麼返回一個串連行,該行的 T1 的欄位
為 null. 同樣,如果 T2 裡有一行對任何 T1 的行都不滿足 串連條件,那麼返回一個串連行,該行的 T2 的欄位 為 null.
小技巧: 串連成的表無條件地擁有來自 T1 的每 一行和來自 T2 的每一行.
所有 類型的 JOIN 都可以連結在一起或者嵌套在一起, 這時 T1 和 T2 都可以是串連產生的表.我們可以使用圓括弧控制 JOIN 的順序,如果我們不主動控制,那麼串連順序是從左至右.
1.4.1.3. 聚集操作符
SQL
提供以一些聚集操作符(如, AVG,COUNT,SUM,MIN,MAX),這些聚集操作符以一個運算式為參數。 只要是滿足 WHERE
子句的行,就會計算這個運算式, 然後聚集操作符對這個輸入數值的集合進行計算. 通常,一個聚集對整個 SELECT 語句計算的結果是
產生一個結果.但如果在一個查詢裡面聲明了分組, 那麼資料庫將對每個組進行一次獨立的計算,並且 聚集結果是按照各個組出現的(見下節).
Example 1-5. 聚集
果我們想知道表 PART 裡面所有組件的平均價格,我們可以使用下面查詢:
SELECT AVG(PRICE) AS AVG_PRICE
FROM PART;
結果是:
AVG_PRICE
-----------
14.5
如果我們想知道在表 PART 裡面儲存了多少組件,我們可以使用語句:
SELECT COUNT(PNO)
FROM PART;
得到:
COUNT
-------
4
1.4.1.4. 分組聚集
SQL 允許我們把一個表裡面的記錄分成組。 然後上面描述的聚集操作符可以應用於這些組上 (也就是說,聚集操作符的值不再是對所有聲明的列的值進行操作, 而是對一個組的所有值進行操作。這樣聚集合函式是為每個組獨立地進行計算的。)
對記錄的分組是通過關鍵字 GROUP BY 實現的,GROUP BY 後面跟著一個定義組的構成的屬性列表。 如果我們使用語句 GROUP BY A1, ⃛, Ak 我們就把關係分成了組,這樣若且唯若兩條記錄在所有屬性 A1, ⃛, Ak 上達成一致,它們才是同一組的。
Example 1-6. 聚集
如果我們想知道每個供應商銷售多少個組件,我們可以這樣寫查詢:
SELECT S.SNO, S.SNAME, COUNT(SE.PNO)
FROM SUPPLIER S, SELLS SE
WHERE S.SNO = SE.SNO
GROUP BY S.SNO, S.SNAME;
得到:
SNO | SNAME | COUNT
-----+-------+-------
1 | Smith | 2
2 | Jones | 1
3 | Adams | 2
4 | Blake | 3
然後我們看一看發生了什麼事情。首先產生表 SUPPLIER 和 SELLS 的串連:
S.SNO | S.SNAME | SE.PNO
-------+---------+--------
1 | Smith | 1
1 | Smith | 2
2 | Jones | 4
3 | Adams | 1
3 | Adams | 3
4 | Blake | 2
4 | Blake | 3
4 | Blake | 4
然後我們把那些屬性 S.SNO 和 S.SNAME 相同的記錄放在組中:
S.SNO | S.SNAME | SE.PNO
-------+---------+--------
1 | Smith | 1
| 2
--------------------------
2 | Jones | 4
--------------------------
3 | Adams | 1
| 3
--------------------------
4 | Blake | 2
| 3
| 4
在我們的例子裡,我們有四個組並且現在我們可以對每個組應用聚集操作符 COUNT,產生上面給出的查詢的最終結果。
請注意如果要讓一個使用 GROUP BY 和聚集操作符的查詢的結果有意義, 那麼用於分組的屬性也必須出現在目標列表中。 所有沒有在 GROUP BY 子句裡面出現的屬性都只能通過使用聚集合函式來選擇。 否則就不會有唯一的數值與其它欄位關聯.
還要注意的是在聚集上聚集是沒有意義的,比如,AVG(MAX(sno)), 因為 SELECT 只做一個回合的分組和聚集.你可以獲得這樣的結果, 方法是使用暫存資料表或者在 FROM 子句中使用一個子 SELECT 做第一個層次的聚集.
1.4.1.5. Having
HAVING
子句運做起來非常象 WHERE 子句, 只用於對那些滿足 HAVING 子句裡面給出的條件的組進行計算。 其實,WHERE
在分組和聚集之前過濾掉我們不需要的輸入行, 而 HAVING 在 GROUP 之後那些不需要的組. 因此,WHERE
無法使用一個聚集合函式的結果. 而另一方面,我們也沒有理由寫一個不涉及聚集合函式的 HAVING. 如果你的條件不包含聚集,那麼你也可以把它寫在
WHERE 裡面, 這樣就可以避免對那些你準備拋棄的行進行的聚集運算.
Example 1-7. Having
如果我們想知道那些銷售超過一個組件的供應商,使用下面查詢:
SELECT S.SNO, S.SNAME, COUNT(SE.PNO)
FROM SUPPLIER S, SELLS SE
WHERE S.SNO = SE.SNO
GROUP BY S.SNO, S.SNAME
HAVING COUNT(SE.PNO) > 1;
and get:
SNO | SNAME | COUNT
-----+-------+-------
1 | Smith | 2
3 | Adams | 2
4 | Blake | 3
1.4.1.6. 子查詢
在 WHERE 和 HAVING 子句裡,允許在任何要產生數值的地方使用子查詢 (子選擇)。 這種情況下,該值必須首先來自對子查詢的計算。子查詢的使用擴充了 SQL 的表達能力。
Example 1-8. 子查詢
如果我們想知道所有比名為 'Screw' 的組件貴的組件,我們可以用下面的查詢:
SELECT *
FROM PART
WHERE PRICE > (SELECT PRICE FROM PART
WHERE PNAME='Screw');
結果是:
PNO | PNAME | PRICE
-----+---------+--------
3 | Bolt | 15
4 | Cam | 25
當
我們檢查上面的查詢時會發現出現了兩次 SELECT 關鍵字。 第一個在查詢的開頭 - 我們將稱之為外層 SELECT - 而另一個在
WHERE 子句裡面,成為一個嵌入的查詢 - 我們將稱之為內層 SELECT。 對外層 SELECT 的每條記錄都必須先計算內層
SELECT。在完成所有計算之後, 我們得知名為 'Screw' 組件的記錄的價格, 然後我們就可以檢查那些價格更貴的記錄了。
(實際上,在本例中,內層查詢只需要執行一次, 因為它不依賴於外層查詢高等狀態.)
如果我們想知道那些不銷售任何組件的供應商 (比如說,我們想把這些供應商從資料庫中刪除),我們用:
SELECT *
FROM SUPPLIER S
WHERE NOT EXISTS
(SELECT * FROM SELLS SE
WHERE SE.SNO = S.SNO);
在
我們的例子裡,結果列將是空的,因為每個供應商至少銷售一個組件。 請注意我們在 WHERE 子句的內層 SELECT 裡使用了來自外層
SELECT 的 S.SNO。 正如前面所說的,子查詢為每個外層查詢計算一次,也就是說, S.SNO 的值總是從外層 SELECT
的實際記錄中取得的。
1.4.1.7. 在 FROM 裡面的子查詢
一種有些特別的子查詢的用法是把它們放在 FROM 子句裡. 這個特性很有用,因為這樣的子查詢可以輸出多列和多行, 而在運算式裡使用的子查詢必鬚生成一個結果. FROM 裡的子查詢還可以讓我們獲得多於一個回合的分組/聚集特性, 而不需要求助於暫存資料表.
Example 1-9. FROM 裡面的子查詢
如果我們想知道在所有我們的供應商中的最高平均組件價格的那家, 我們不能用 MAX(AVG(PRICE)),但我們可以這麼寫:
SELECT MAX(subtable.avgprice)
FROM (SELECT AVG(P.PRICE) AS avgprice
FROM SUPPLIER S, PART P, SELLS SE
WHERE S.SNO = SE.SNO AND
P.PNO = SE.PNO
GROUP BY S.SNO) subtable;
這個子查詢為每個供應商返回一行(因為它的 GROUP BY) 然後我們在外層查詢對所有行進行聚集.
1.4.1.8. Union, Intersect, Except(聯合,相交,相異)
這些操作符分別計算兩個子查詢產生的元組的聯合,相交和集合理論裡的相異。
Example 1-10. Union, Intersect, Except
下面的例子是 UNION 的例子:
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNAME = 'Jones'
UNION
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNAME = 'Adams';
產生結果:
SNO | SNAME | CITY
-----+-------+--------
2 | Jones | Paris
3 | Adams | Vienna
下面是相交( INTERSECT)的例子:
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNO > 1
INTERSECT
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNO < 3;
產生結果:
SNO | SNAME | CITY
-----+-------+--------
2 | Jones | Paris
兩個查詢都會返回的元組是那條 SNO=2 的
最後是一個 EXCEPT 的例子:
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNO > 1
EXCEPT
SELECT S.SNO, S.SNAME, S.CITY
FROM SUPPLIER S
WHERE S.SNO > 3;
結果是:
SNO | SNAME | CITY
-----+-------+--------
2 | Jones | Paris
3 | Adams | Vienna
作者Blog:http://blog.csdn.net/meskgron/相關文章
| 基於ASP.NET實現全球化 |
| SQL select 文法 |
| ADO 與ADO.NET |
| JDBC串連資料庫格式 |
| JavaBean實現多檔案上傳的兩種方法 |