整理自網(wǎng)絡,我也忘了從哪個網(wǎng)站了。
一、SQL是一種聲明式語言
首先要把這個概念記在腦中:“聲明”。 SQL 語言是為計算機聲明了一個你想從原始數(shù)據(jù)中獲得什么樣的結果的一個范例,而不是告訴計算機如何能夠得到結果。
簡單地說,SQL 語言聲明的是結果集的屬性,計算機會根據(jù) SQL 所聲明的內(nèi)容來從數(shù)據(jù)庫中挑選出符合聲明的數(shù)據(jù)。
二、SQL的語法并不按照語法順序執(zhí)行
SQL 語句有一個讓大部分人都感到困惑的特性,就是:SQL 語句的執(zhí)行順序跟其語句的語法順序并不一致。SQL 語句的執(zhí)行順序是:
<ol>
<li>FROM</li>
<li>WHERE</li>
<li>GROUP BY</li>
<li>HAVING</li>
<li>SELECT</li>
<li>DISTINCT</li>
<li>UNION</li>
<li>ORDER BY</li>
</ol>
關于 SQL 語句的執(zhí)行順序,有兩個值得我們注意的地方:
FROM才是SQL語句執(zhí)行的第一步,并非 SELECT 。數(shù)據(jù)庫在執(zhí)行 SQL 語句的第一步是將數(shù)據(jù)從硬盤加載到數(shù)據(jù)緩沖區(qū)中,以便對這些數(shù)據(jù)進行操作。但是并非如此,以 Oracle 等常用數(shù)據(jù)庫為例,數(shù)據(jù)是從硬盤中抽取到數(shù)據(jù)緩沖區(qū)中進行操作。
SELECT 是在大部分語句執(zhí)行了之后才執(zhí)行的,理解這一點是非常重要的,這就是你不能在 WHERE 中使用在 SELECT 中設定別名的字段作為判斷條件的原因。
SELECT A.x + A.y AS z
FROM A
WHERE z = 10 // z在此處不可用,因為SELECT是最后執(zhí)行的語句
永遠要記得: SQL 語句的語法順序和其執(zhí)行順序并不一致,這樣我們就能避免一般性的錯誤。
三、SQL語言的核心是對表的引用
FROM 語句的“輸出”是一張聯(lián)合表,來自于所有引用的表在某一維度上的聯(lián)合。
FROM a, b
上面這句 FROM 語句的輸出是一張聯(lián)合表,聯(lián)合了表 a 和表 b 。如果 a 表有三個字段, b 表有 5 個字段,那么這個“輸出表”就有 8 個字段。
四、SQL語句中推薦使用表連接
我們先看看剛剛這句話:
FROM a, b
高級SQL程序員也許會給你忠告:盡量不要使用逗號來代替JOIN進行表的連接,這樣會提高你的 SQL 語句的可讀性,并且可以避免一些錯誤。
想一下下面的語句:
FROM a, b, c, d, e, f, g, h
WHERE a.a1 = b.bx
AND a.a2 = c.c1
AND d.d1 = b.bc
-- etc...
要使用:
FROM a
JOIN b
ON a.id = b.id
五、SQL語句中不同的連接操作
SQL 語句中,表連接的方式從根本上分為五種:
? EQUI JOIN(等值連接)
? SEMI JOIN(半連接)
? ANTI JOIN(反連接)
? CROSS JOIN(交叉連接)
? DIVISION
5.1 EQUI JOIN(等值連接)
這是一種最普通的 JOIN 操作,它包含兩種連接方式:
- INNER JOIN(或者是 JOIN )內(nèi)連接
- OUTER JOIN(包括: LEFT 、 RIGHT、 FULL OUTER JOIN)外連接
5.2 SEMI JOIN(半連接)
這種連接關系在 SQL 中有兩種表現(xiàn)方式:使用IN,或者使用EXISTS?!?SEMI ”在拉丁文中是“半”的意思。這種連接方式是只連接目標表的一部分。
FROM author
WHERE author.id IN (SELECT book.author_id FROM book)
或者
FROM author
WHERE EXISTS (SELECT * FROM book WHERE book.author_id = author.id)
盡管沒有嚴格的規(guī)定說明你何時應該使用 IN ,何時應該使用 EXISTS ,但是這些事情你還是應該知道的:
? IN比 EXISTS 的可讀性更好
? EXISTS 比IN 的表達性更好(更適合復雜的語句)
? 二者之間性能沒有差異(但對于某些數(shù)據(jù)庫來說性能差異會非常大)
因為使用 INNER JOIN 也能得到書名表中書所對應的作者信息,所以很多初學者機會認為可以通過 DISTINCT 進行去重,然后將 SEMI JOIN 語句寫成這樣:
SELECT DISTINCT first_name, last_name
FROM author
JOIN book ON author.id = book.author_id
這是一種很糟糕的寫法,原因如下:
? SQL 語句性能低下:因為去重操作( DISTINCT )需要數(shù)據(jù)庫重復從硬盤中讀取數(shù)據(jù)到內(nèi)存中。
? 這么寫并非完全正確:盡管也許現(xiàn)在這么寫不會出現(xiàn)問題,但是隨著 SQL 語句變得越來越復雜,你想要去重得到正確的結果就變得十分困難。
5.3 ANTI JOIN(反連接)
這種連接的關系跟 SEMI JOIN 剛好相反。在 IN 或者 EXISTS 前加一個 NOT 關鍵字就能使用這種連接。舉個例子來說,我們列出書名表里沒有書的作者:
FROM author
WHERE author.id
NOT IN (SELECT book.author_id FROM book)
或者
FROM author
WHERE NOT EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)
5.4 CROSS JOIN(交叉連接)
這個連接過程就是兩個連接的表的乘積:即將第一張表的每一條數(shù)據(jù)分別對應第二張表的每條數(shù)據(jù)。我們之前見過,這就是逗號在 FROM 語句中的用法。
六、SQL中如同變量的派生表
在這之前,我們學習到過 SQL 是一種聲明性的語言,并且 SQL 語句中不能包含變量。但是你能寫出類似于變量的語句,這些就叫做派生表。說白了,所謂的派生表就是在括號之中的子查詢。
FROM (SELECT * FROM author)
需要注意的是有些時候我們可以給派生表定義一個相關名(即我們所說的別名)。
FROM (SELECT * FROM author) a
七、SQL語句中 GROUP BY 是對表的引用進行的操作
讓我們再回想一下之前的 FROM 語句:
FROM a, b
現(xiàn)在,我們將 GROUP BY 應用到上面的語句中:
GROUP BY A.x, A.y, B.z
上面語句的結果就是產(chǎn)生出了一個包含三個字段的新的表的引用。我們來仔細理解一下這句話:當你是用 GROUP BY 的時候,你能夠對其進行下一級邏輯操作的列會減少,包括在 SELECT 中的列。沒有使用聚合函數(shù)又不是GROUP BY的字段如果出現(xiàn)在SELECT后會報錯。
需要注意的是其他字段能夠使用聚合函數(shù):
SELECT A.x, A.y, SUM(A.z)
FROM A
GROUP BY A.x, A.y
八、SQL 語句中的 SELECT 實質上是對關系的映射
一旦你建立起來了表的引用,經(jīng)過修改、變形,你能夠一步一步的將其映射到另一個模型中。 SELECT 語句就像一個“投影儀”,我們可以將其理解成一個將源表中的數(shù)據(jù)按照一定的邏輯轉換成目標表數(shù)據(jù)的函數(shù)。
SELECT 語句可能是 SQL 語句中最難的部分了,盡管他看上去很簡單。其他語句的作用其實就是對表的不同形式的引用。而 SELECT 語句則把這些引用整合在了一起,通過邏輯規(guī)則將源表映射到目標表,而且這個過程是可逆的,我們可以清楚的知道目標表的數(shù)據(jù)是怎么來的。
想要學習好 SQL 語言,就要在使用 SELECT 語句之前弄懂其他的語句,雖然 SELECT 是語法結構中的第一個關鍵詞,但它應該是我們最后一個掌握的。
九、SQL 語句中的幾個簡單的關鍵詞: DISTINCT , UNION , ORDER BY 和 OFFSET
- 集合運算( DISTINCT 和 UNION )
- 排序運算( ORDER BY,OFFSET…FETCH)
集合運算主要操作在于集合上,事實上指的就是對表的一種操作。從概念上來說,他們很好理解:
- DISTINCT 在映射之后對數(shù)據(jù)進行去重
- UNION 將兩個子查詢拼接起來并去重
- UNION ALL 將兩個子查詢拼接起來但不去重
- EXCEPT 將第二個字查詢中的結果從第一個子查詢中去掉
- INTERSECT 保留兩個子查詢中都有的結果并去重
排序運算跟邏輯關系無關。這是一個 SQL 特有的功能。排序運算不僅在 SQL 語句的最后,而且在 SQL 語句運行的過程中也是最后執(zhí)行的。使用 ORDER BY 和 OFFSET…FETCH 是保證數(shù)據(jù)能夠按照順序排列的最有效的方式。
OFFSET…SET是一個沒有統(tǒng)一確定語法的語句,不同的數(shù)據(jù)庫有不同的表達方式,如 MySQL 和 PostgreSQL 的 LIMIT…OFFSET、SQL Server 和 Sybase 的 TOP…START AT 等。
正如其他語言一樣,想要學好 SQL 語言就要大量的練習。