第一部分:SQL基礎(chǔ)
1. 為什么學(xué)習(xí)SQL自人類(lèi)社會(huì)形成之日起,社會(huì)的運(yùn)轉(zhuǎn)就在不斷地產(chǎn)生和使用各種信息(文獻(xiàn)、檔案、資料、數(shù)據(jù)等);在如今所謂的信息時(shí)代,由于計(jì)算機(jī)和互聯(lián)網(wǎng)的作用,信息的產(chǎn)生和使用達(dá)到前所未有的廣度和深度。如何管好和用好信息,是(而且將一直是)IT行業(yè)一塊重要的領(lǐng)域。
在過(guò)去幾十年中,關(guān)系數(shù)據(jù)庫(kù)一直在這一領(lǐng)域占主導(dǎo)地位,而建立在關(guān)系理論基礎(chǔ)之上的SQL也成為數(shù)據(jù)庫(kù)領(lǐng)域的既定標(biāo)準(zhǔn)。
目前的數(shù)據(jù)存儲(chǔ)領(lǐng)域可稱為三分天下:
a. 少量數(shù)據(jù)的存儲(chǔ):
自定義數(shù)據(jù)文件或通用數(shù)據(jù)文件(單機(jī)數(shù)據(jù)庫(kù)),通過(guò)自定義接口或通用API訪問(wèn)數(shù)據(jù)。如需要存儲(chǔ)數(shù)據(jù)的單機(jī)軟件或小型的動(dòng)態(tài)網(wǎng)站。
b. 對(duì)一致性要求高的大量數(shù)據(jù)的存儲(chǔ):
關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)。如各種傳統(tǒng)的信息系統(tǒng)(ERP、CRM、HRMS、MIS等)。
c. 對(duì)并發(fā)性要求高的大量數(shù)據(jù)的存儲(chǔ):
NoSQL數(shù)據(jù)庫(kù)系統(tǒng)。如Web2.0網(wǎng)站的后臺(tái)數(shù)據(jù)系統(tǒng)。
以上,“狐假虎威”地借數(shù)據(jù)存儲(chǔ)的重要性來(lái)闡述了一番學(xué)習(xí)SQL的偉大意義。但重要的是,對(duì)SQL善于做什么和不善于做什么有個(gè)清楚的認(rèn)識(shí)。
2. 學(xué)習(xí)SQL的參考資料不久前整理了
數(shù)據(jù)庫(kù)圖書(shū)ABC一文,對(duì)數(shù)據(jù)庫(kù)相關(guān)的參考資料作了粗略的分類(lèi)。
對(duì)于初學(xué)者而言,可以結(jié)合著《數(shù)據(jù)庫(kù)系統(tǒng)概念(第5版)》一書(shū)和某個(gè)DBMS平臺(tái)的入門(mén)技術(shù)手冊(cè)練習(xí),自行尋找或構(gòu)思一個(gè)小需求,建一個(gè)數(shù)據(jù)庫(kù),創(chuàng)建幾個(gè)表和視圖,練習(xí)寫(xiě)查詢和修改語(yǔ)句?;A(chǔ)理論和技術(shù)實(shí)踐可以相互促進(jìn)。
3. 幾組基本概念3.1. 單機(jī)數(shù)據(jù)庫(kù)與服務(wù)器級(jí)數(shù)據(jù)庫(kù)單機(jī)數(shù)據(jù)庫(kù)(如sqlite、Access等,Excel也勉強(qiáng)可以算是)是應(yīng)用于單個(gè)計(jì)算機(jī)的數(shù)據(jù)庫(kù)引擎,通常不具備網(wǎng)絡(luò)連接功能,適用于小型應(yīng)用;程序部署時(shí),一般只需要附帶數(shù)據(jù)文件即可。有時(shí)也稱作桌面數(shù)據(jù)庫(kù)。
服務(wù)器級(jí)數(shù)據(jù)庫(kù)(如Oracle、DB2、SQL Server、MySQL、PostgreSQL等)是具備網(wǎng)絡(luò)連接功能、可作為單獨(dú)數(shù)據(jù)庫(kù)服務(wù)器的DBMS,適用于大型信息系統(tǒng);程序部署時(shí),需要專(zhuān)門(mén)安裝相應(yīng)的DBMS,甚至要單獨(dú)進(jìn)行數(shù)據(jù)庫(kù)服務(wù)器的架構(gòu)設(shè)計(jì)。此類(lèi)數(shù)據(jù)庫(kù)是我們討論的重點(diǎn)。
3.2. 服務(wù)器(Server)與客戶端(Client)數(shù)據(jù)庫(kù)服務(wù)器是運(yùn)行在一臺(tái)主機(jī)(Host)(或主機(jī)集群)上的服務(wù)程序,維護(hù)著一個(gè)或多個(gè)數(shù)據(jù)庫(kù),并通過(guò)網(wǎng)絡(luò)連接響應(yīng)數(shù)據(jù)庫(kù)客戶端提交的SQL語(yǔ)句。
數(shù)據(jù)庫(kù)客戶端是向數(shù)據(jù)庫(kù)服務(wù)器發(fā)送查詢請(qǐng)求的應(yīng)用程序,可能是DBMS的GUI管理界面或命令行應(yīng)用程序,也可能是前端的Web服務(wù)器。數(shù)據(jù)庫(kù)客戶端和數(shù)據(jù)庫(kù)服務(wù)器可能是在同一臺(tái)主機(jī)上,但更多情況下則是位于不同的主機(jī)上,通過(guò)局域網(wǎng)訪問(wèn)。
例如對(duì)于SQL Server來(lái)說(shuō),一個(gè)服務(wù)器實(shí)例(Instance)即是一個(gè)數(shù)據(jù)庫(kù)服務(wù)器,一臺(tái)主機(jī)上可以安裝多個(gè)服務(wù)器實(shí)例;而查詢分析器或SSMS、sqlcmd、以及連接數(shù)據(jù)庫(kù)服務(wù)器的IIS,都是數(shù)據(jù)庫(kù)客戶端。
比如你在SSMS中備份/還原/附加一個(gè)數(shù)據(jù)庫(kù),或是通過(guò)xp_cmdshell執(zhí)行一個(gè)命令程序,所操作的都是你所連接的數(shù)據(jù)庫(kù)服務(wù)器所在主機(jī)的文件,而不是你運(yùn)行SSMS數(shù)據(jù)庫(kù)客戶端所在主機(jī)的文件。
一臺(tái)主機(jī)有時(shí)候會(huì)被稱作一臺(tái)(操作系統(tǒng))服務(wù)器,而數(shù)據(jù)庫(kù)服務(wù)器和Web服務(wù)器都是運(yùn)行在主機(jī)之上的應(yīng)用服務(wù)器。它們都被稱作服務(wù)器,不要因此搞混了。
一個(gè)典型的基于SQL Server的網(wǎng)站系統(tǒng)的架構(gòu)示例如下:
用戶瀏覽器(Web Client) <----> IIS(Web Server/DB Client) <----> SQL Server(DB Server)
3.3. 數(shù)據(jù)庫(kù)(DB)與數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)“數(shù)據(jù)庫(kù)”這個(gè)詞已經(jīng)被濫用,可能用來(lái)指一個(gè)數(shù)據(jù)系統(tǒng)(如中國(guó)移動(dòng)的號(hào)碼數(shù)據(jù)庫(kù)),可能用來(lái)指一種數(shù)據(jù)存儲(chǔ)技術(shù)(如關(guān)系數(shù)據(jù)庫(kù)和NoSQL數(shù)據(jù)庫(kù)),還可能用來(lái)指DBMS(如人們常說(shuō)SQL Server是數(shù)據(jù)庫(kù)軟件)。這種混亂已然形成,恐怕難以改變(比如上文的描述即是如此)。我們只能根據(jù)上下文來(lái)判斷具體含義。
按最狹義的技術(shù)含義,數(shù)據(jù)庫(kù)(Database)是指位于一個(gè)數(shù)據(jù)庫(kù)服務(wù)器實(shí)例上的一個(gè)庫(kù),而DBMS則是指類(lèi)似SQL Server、Oracle等等此類(lèi)軟件。初學(xué)者要注意這些概念之間的差別。論壇上常常見(jiàn)到這樣的帖子:“連不上數(shù)據(jù)庫(kù)”、“數(shù)據(jù)庫(kù)打不開(kāi)了”,又沒(méi)有上下文,可見(jiàn)發(fā)問(wèn)者概念混亂,搞得解答者也是一頭霧水。
3.4. SQL與SQL方言(dialect)SQL是一個(gè)關(guān)系數(shù)據(jù)庫(kù)查詢語(yǔ)言的標(biāo)準(zhǔn),而SQL方言則是各種DBMS在SQL標(biāo)準(zhǔn)上進(jìn)行的擴(kuò)展,如增加新的關(guān)鍵字、查詢功能、特有的數(shù)據(jù)類(lèi)型、支持過(guò)程化的控制流語(yǔ)句等。例如SQL Server的T-SQL和Oracle的PL/SQL都是常見(jiàn)的SQL方言。
這就好比ANSI C標(biāo)準(zhǔn)與各種編譯器實(shí)現(xiàn)的C語(yǔ)言的差別。但不同SQL方言之間的差異遠(yuǎn)大于不同C編譯器之間的差異。SQL方言之間的差異,對(duì)于跨DBMS的學(xué)習(xí)和開(kāi)發(fā),都是必須注意的。
3.5. 語(yǔ)句、表達(dá)式和斷言語(yǔ)句(statement)是SQL中一個(gè)可以單獨(dú)執(zhí)行的單元。如SELECT * FROM table;即是一個(gè)語(yǔ)句,其中包含了SELECT子句(clause)和FROM子句。SQL標(biāo)準(zhǔn)規(guī)定用分號(hào)作為語(yǔ)句的結(jié)束,但在目前的T-SQL中,語(yǔ)句結(jié)束的分號(hào)是可選的。
表達(dá)式(expression)是SQL中的一個(gè)值(可能是變量、常量、查詢字段或計(jì)算結(jié)果),對(duì)應(yīng)一種特定的數(shù)據(jù)類(lèi)型。SQL中的表達(dá)式分為標(biāo)量表達(dá)式和表值表達(dá)式,其中表值表達(dá)式作為單獨(dú)語(yǔ)句則是SELECT語(yǔ)句,作為語(yǔ)句的一部分則稱為子查詢。比如0, col + 2, DATEADD(second, 30, GETDATE())都是(標(biāo)量)表達(dá)式。
需要特別說(shuō)明的是,SQL中的CASE WHEN是標(biāo)題表達(dá)式,而不是條件語(yǔ)句。比如CASE WHEN中可以使用表達(dá)式,卻不能使用語(yǔ)句;CASE WHEN的結(jié)果是一個(gè)特定數(shù)據(jù)類(lèi)型的標(biāo)量值;CASE WHEN可以用在SELECT、GROUP BY或ORDER BY子句中,但I(xiàn)F ELSE則不行。
斷言(predicate)是SQL中進(jìn)行比較的結(jié)果,即真值,可理解為布爾表達(dá)式,因?yàn)镾QL中沒(méi)有bool數(shù)據(jù)類(lèi)型,所以將斷言特別從表達(dá)式中區(qū)分出來(lái)。比如1是一個(gè)標(biāo)量表達(dá)式,而1 = 1則是一個(gè)斷言,后者可以用在WHERE、ON、HAVING、CHECK等需要真值條件的地方,但前者則不可以。由于NULL的存在,SQL中的斷言是三值邏輯,即True/False/Unknown,詳見(jiàn)下文“NULL與三值邏輯”。
下文中多次用到計(jì)算和比較兩個(gè)詞。表達(dá)式和表達(dá)式進(jìn)行計(jì)算,結(jié)果是新的表達(dá)式;表達(dá)式和表達(dá)式進(jìn)行比較,結(jié)果是一個(gè)斷言;斷言和斷言可以進(jìn)行邏輯運(yùn)行(AND/OR/NOT),結(jié)果是新的斷言。注意其中的區(qū)別。
4. SQL不同于一般編程語(yǔ)言的地方4.1. SQL操作的是數(shù)據(jù)SQL是數(shù)據(jù)庫(kù)的查詢語(yǔ)言,因而可以對(duì)系統(tǒng)數(shù)據(jù)產(chǎn)生持久化影響。在常規(guī)編程中,一個(gè)錯(cuò)誤通常只會(huì)造成程序的crash或bug,修改并重新調(diào)試往往就可以了;而在SQL中,一個(gè)不小心就可能造成系統(tǒng)數(shù)據(jù)的破壞和丟失。常常有新手執(zhí)行SQL時(shí),不小心遺漏了DELETE或UPDATE語(yǔ)句中的WHERE子句,這往往是很大的麻煩。
因此,學(xué)習(xí)和使用SQL,一開(kāi)始應(yīng)該養(yǎng)成兩個(gè)習(xí)慣:
1.
細(xì)心。在執(zhí)行SQL語(yǔ)句認(rèn)真檢查一下,要清楚自己在做什么。
2.
及時(shí)備份,并考慮對(duì)系統(tǒng)的元數(shù)據(jù)進(jìn)行
版本控制。為偶爾的意外準(zhǔn)備好后悔藥。
常見(jiàn)的可能造成破壞性影響的SQL關(guān)鍵詞:DELETE, UPDATE, DROP, TRUNCATE TABLE。
4.2. SQL是基于集合的說(shuō)明式語(yǔ)言SQL擅長(zhǎng)集合操作,而不是循環(huán)。所謂說(shuō)明式語(yǔ)言,你只需要告訴SQL需要做什么,而不是怎么做。
初學(xué)SQL的人,思維往往難免帶有過(guò)程式語(yǔ)言的痕跡,解決問(wèn)題時(shí)常常不由地考慮循環(huán)。在學(xué)習(xí)SQL編程時(shí),每當(dāng)想要用循環(huán)時(shí),先反問(wèn)一下自己:
這個(gè)問(wèn)題是不是必須用循環(huán)來(lái)解決?事實(shí)上,多數(shù)情況下,這個(gè)問(wèn)題的答案是否定的。
有本書(shū)中講,SQL代碼中出現(xiàn)一次IF便要減一些分(比如-1),出現(xiàn)一次WHILE便要減很多分(比如-10或-50,不夸張)??梢試L試用這樣的方法為自己的存儲(chǔ)過(guò)程打分。
5. SQL的三個(gè)子集SQL從功能上可以劃分為三個(gè)子集:
1. DML(Data Manipulation Language):
數(shù)據(jù)操縱語(yǔ)言,是對(duì)數(shù)據(jù)進(jìn)行查詢和修改(增、刪、改)操作的語(yǔ)言。
包含語(yǔ)句:SELECT+INSERT/DELETE/UPDATE
使用對(duì)象:DB User
2. DDL(Data Definition Language):
數(shù)據(jù)定義語(yǔ)言,是對(duì)域(數(shù)據(jù)類(lèi)型)和關(guān)系(表)及其它數(shù)據(jù)庫(kù)對(duì)象進(jìn)行定義的語(yǔ)言。
包含語(yǔ)句:CREATE/DROP/ALTER
使用對(duì)象:DB Designer/Developer
3. DCL(Data Control Language):
數(shù)據(jù)控制語(yǔ)言:是對(duì)數(shù)據(jù)的訪問(wèn)進(jìn)行權(quán)限控制的語(yǔ)言。
包含語(yǔ)句:GRANT/DENY/REVOKE
使用對(duì)象:DBA
補(bǔ)充說(shuō)明:
- 嚴(yán)格地說(shuō),DML只包含對(duì)數(shù)據(jù)進(jìn)行修改的語(yǔ)句(INSERT/DELETE/UPDATE),但SELECT語(yǔ)句與DML關(guān)系緊密、形式類(lèi)似,故通常放在一起。既可以統(tǒng)稱為DML,也可以并稱為Query+DML。
- 以上三個(gè)子集不包含BACKUP/RESTORE語(yǔ)句。