??什么是SQL
SQL就是訪問和處理關(guān)系數(shù)據(jù)庫的計(jì)算機(jī)標(biāo)準(zhǔn)語言。也就是說,無論用什么編程語言(Java、Python、C++……)編寫程序,只要涉及到操作關(guān)系數(shù)據(jù)庫,比如,一個(gè)電商網(wǎng)站需要把用戶和商品信息存入數(shù)據(jù)庫,或者一個(gè)手機(jī)游戲需要把用戶的道具、通關(guān)信息存入數(shù)據(jù)庫,都必須通過SQL來完成。所以,現(xiàn)代程序離不開關(guān)系數(shù)據(jù)庫,要使用關(guān)系數(shù)據(jù)庫就必須掌握SQL。
SQL的全稱是Structured Query Language,即結(jié)構(gòu)化查詢語言。SQL語句既可以查詢數(shù)據(jù)庫中的數(shù)據(jù),也可以添加、更新和刪除數(shù)據(jù)庫中的數(shù)據(jù),還可以對(duì)數(shù)據(jù)庫進(jìn)行管理和維護(hù)操作。
SQL語言定義了以下幾種操作數(shù)據(jù)庫的能力:
DDL:Data Definition Language
DDL允許用戶定義數(shù)據(jù),也就是創(chuàng)建表、刪除表、修改表結(jié)構(gòu)這些操作。通常,DDL由數(shù)據(jù)庫管理員執(zhí)行。
DML:Data Manipulation Language
DML為用戶提供添加、刪除、更新數(shù)據(jù)的能力,這些是應(yīng)用程序?qū)?shù)據(jù)庫的日常操作。
DQL:Data Query Language
DQL允許用戶查詢數(shù)據(jù),這也是通常最頻繁的數(shù)據(jù)庫日常操作。
為什么需要數(shù)據(jù)庫?
因?yàn)閼?yīng)用程序需要保存用戶的數(shù)據(jù),比如Word需要把用戶文檔保存起來,以便下次繼續(xù)編輯或者拷貝到另一臺(tái)電腦。
要保存用戶的數(shù)據(jù),一個(gè)最簡單的方法是把用戶數(shù)據(jù)寫入文件。例如,要保存一個(gè)班級(jí)所有學(xué)生的信息,可以向文件中寫入一個(gè)CSV文件:
id,name,gender,score
1,小明,M,90
2,小紅,F,95
3,小軍,M,88
4,小麗,F,88
如果要保存學(xué)校所有班級(jí)的信息,可以寫入另一個(gè)CSV文件。
但是,隨著應(yīng)用程序的功能越來越復(fù)雜,數(shù)據(jù)量越來越大,如何管理這些數(shù)據(jù)就成了大問題:
讀寫文件并解析出數(shù)據(jù)需要大量重復(fù)代碼;
從成千上萬的數(shù)據(jù)中快速查詢出指定數(shù)據(jù)需要復(fù)雜的邏輯。
如果每個(gè)應(yīng)用程序都各自寫自己的讀寫數(shù)據(jù)的代碼,一方面效率低,容易出錯(cuò),另一方面,每個(gè)應(yīng)用程序訪問數(shù)據(jù)的接口都不相同,數(shù)據(jù)難以復(fù)用。
所以,數(shù)據(jù)庫作為一種專門管理數(shù)據(jù)的軟件就出現(xiàn)了。應(yīng)用程序不需要自己管理數(shù)據(jù),而是通過數(shù)據(jù)庫軟件提供的接口來讀寫數(shù)據(jù)。至于數(shù)據(jù)本身如何存儲(chǔ)到文件,那是數(shù)據(jù)庫軟件的事情,應(yīng)用程序自己并不關(guān)心:

這樣一來,編寫應(yīng)用程序的時(shí)候,數(shù)據(jù)讀寫的功能就被大大地簡化了。
數(shù)據(jù)庫的結(jié)構(gòu)模型
數(shù)據(jù)庫按照數(shù)據(jù)結(jié)構(gòu)來組織、存儲(chǔ)和管理數(shù)據(jù),實(shí)際上,數(shù)據(jù)庫一共有三種模型:
層次模型:以“上下級(jí)”的層次關(guān)系來組織數(shù)據(jù)的一種方式,層次模型的數(shù)據(jù)結(jié)構(gòu)看起來就像一顆樹
網(wǎng)狀模型:把每個(gè)數(shù)據(jù)節(jié)點(diǎn)和其他很多節(jié)點(diǎn)都連接起來,它的數(shù)據(jù)結(jié)構(gòu)看起來就像很多城市之間的路網(wǎng)
關(guān)系模型:把數(shù)據(jù)看作是一個(gè)二維表格,任何數(shù)據(jù)都可以通過行號(hào)+列號(hào)來唯一確定,它的數(shù)據(jù)模型看起來就是一個(gè)Excel表
??關(guān)系數(shù)據(jù)庫
隨著時(shí)間的推移和市場(chǎng)競(jìng)爭,最終,基于關(guān)系模型的關(guān)系數(shù)據(jù)庫獲得了絕對(duì)市場(chǎng)份額。相比層次模型和網(wǎng)狀模型,關(guān)系模型理解和使用起來最簡單。關(guān)系模型本質(zhì)上就是若干個(gè)存儲(chǔ)數(shù)據(jù)的二維表,可以把它們看作很多Excel表。和Excel表有所不同的是,關(guān)系數(shù)據(jù)庫的表和表之間需要建立“一對(duì)多”,“多對(duì)一”和“一對(duì)一”的關(guān)系,這樣才能夠按照應(yīng)用程序的邏輯來組織和存儲(chǔ)數(shù)據(jù)。
表的每一行稱為記錄(Record),記錄是一個(gè)邏輯意義上的數(shù)據(jù)。
表的每一列稱為字段(Column),同一個(gè)表的每一行記錄都擁有相同的若干字段。字段定義了數(shù)據(jù)類型(整型、浮點(diǎn)型、字符串、日期等),以及是否允許為NULL。注意NULL表示字段數(shù)據(jù)不存在。一個(gè)整型字段如果為NULL不表示它的值為0,同樣的,一個(gè)字符串型字段為NULL也不表示它的值為空串''。

在關(guān)系數(shù)據(jù)庫中,關(guān)系是通過主鍵和外鍵來維護(hù)的。
?主鍵
在關(guān)系數(shù)據(jù)庫中,一張表中的每一行數(shù)據(jù)被稱為一條記錄。每一條記錄都包含若干定義好的字段。同一個(gè)表的所有記錄都有相同的字段定義。對(duì)于關(guān)系表,有個(gè)很重要的約束,就是任意兩條記錄不能重復(fù)。不能重復(fù)不是指兩條記錄不完全相同,而是指能夠通過某個(gè)字段唯一區(qū)分出不同的記錄,這個(gè)字段被稱為主鍵。
例如,假設(shè)我們把name字段作為主鍵,那么通過名字小明或小紅就能唯一確定一條記錄。但是,這么設(shè)定,就沒法存儲(chǔ)同名的同學(xué)了,因?yàn)椴迦胂嗤麈I的兩條記錄是不被允許的。
對(duì)主鍵的要求,最關(guān)鍵的一點(diǎn)是:記錄一旦插入到表中,主鍵最好不要再修改,因?yàn)橹麈I是用來唯一定位記錄的,修改了主鍵,會(huì)造成一系列的影響。選取主鍵的一個(gè)基本原則是:不使用任何業(yè)務(wù)相關(guān)的字段作為主鍵。
因此,身份證號(hào)、手機(jī)號(hào)、郵箱地址這些看上去可以唯一的字段,均不可用作主鍵。作為主鍵最好是完全業(yè)務(wù)無關(guān)的字段,我們一般把這個(gè)字段命名為id。
關(guān)系數(shù)據(jù)庫實(shí)際上還允許通過多個(gè)字段唯一標(biāo)識(shí)記錄,即兩個(gè)或更多的字段都設(shè)置為主鍵,這種主鍵被稱為聯(lián)合主鍵。對(duì)于聯(lián)合主鍵,允許一列有重復(fù),只要不是所有主鍵列都重復(fù)即可。
?外鍵
外鍵用來和其他表建立聯(lián)系,表的外鍵是另一表的主鍵,外鍵是可以有重復(fù)的,可以是空值。
?索引
在關(guān)系數(shù)據(jù)庫中,如果有上萬甚至上億條記錄,在查找記錄的時(shí)候,想要獲得非??斓乃俣龋托枰褂盟饕?。
索引是關(guān)系數(shù)據(jù)庫中對(duì)某一列或多個(gè)列的值進(jìn)行預(yù)排序的數(shù)據(jù)結(jié)構(gòu)。通過使用索引,可以讓數(shù)據(jù)庫系統(tǒng)不必掃描整個(gè)表,而是直接定位到符合條件的記錄,這樣就大大加快了查詢速度。
索引的效率取決于索引列的值是否散列,即該列的值如果越互不相同,那么索引效率越高。反過來,如果記錄的列存在大量相同的值,例如gender列,大約一半的記錄值是M,另一半是F,因此,對(duì)該列創(chuàng)建索引就沒有意義。
可以對(duì)一張表創(chuàng)建多個(gè)索引。索引的優(yōu)點(diǎn)是提高了查詢效率,缺點(diǎn)是在插入、更新和刪除記錄時(shí),需要同時(shí)修改索引,因此,索引越多,插入、更新和刪除記錄的速度就越慢。
對(duì)于主鍵,關(guān)系數(shù)據(jù)庫會(huì)自動(dòng)對(duì)其創(chuàng)建主鍵索引。使用主鍵索引的效率是最高的,因?yàn)橹麈I會(huì)保證絕對(duì)唯一。
查詢數(shù)據(jù)庫的基本語句
1. 指定查詢
要查詢數(shù)據(jù)庫表所有行和所有列的數(shù)據(jù),我們使用如下的SQL語句:
SELECT * FROM<表名>;
SELECT是關(guān)鍵字,表示將要執(zhí)行一個(gè)查詢,*表示“所有列”,F(xiàn)ROM表示將要從哪個(gè)表查詢,本例中是students表。SELECT查詢的結(jié)果是一個(gè)二維表。
2. 條件查詢
使用SELECT * FROM <表名>可以查詢到一張表的所有記錄。但是,很多時(shí)候,我們并不希望獲得所有記錄,而是根據(jù)條件選擇性地獲取指定條件的記錄,例如,查詢分?jǐn)?shù)在80分以上的學(xué)生記錄。在一張表有數(shù)百萬記錄的情況下,獲取所有記錄不僅費(fèi)時(shí),還費(fèi)內(nèi)存和網(wǎng)絡(luò)帶寬。
SELECT語句可以通過WHERE條件來設(shè)定查詢條件,查詢結(jié)果是滿足查詢條件的記錄。例如,要指定條件“分?jǐn)?shù)在80分或以上的學(xué)生”,寫成WHERE條件就是:
SELECT * FROM students WHERE score >= 80;
條件表達(dá)式可以用<條件1> AND <條件2>表達(dá)滿足條件1并且滿足條件2。例如,符合條件“分?jǐn)?shù)在80分或以上”,并且還符合條件“男生”,把這兩個(gè)條件寫出來:
SELECT * FROM students WHERE score >= 80 AND gender = 'M';
第I二種條件是<條件1> OR <條件2>,表示滿足條件1或者滿足條件2。例如,把上述AND查詢的兩個(gè)條件改為OR,查詢結(jié)果就是“分?jǐn)?shù)在80分或以上”或者“男生”,滿足任意之一的條件即選出該記錄:
SELECT * FROM students WHERE?score >= 80 OR gender = 'M';
很顯然OR條件要比AND條件寬松,返回的符合條件的記錄也更多。
第三種條件是NOT <條件>,表示“不符合該條件”的記錄。例如,寫一個(gè)“不是2班的學(xué)生”這個(gè)條件,可以先寫出“是2班的學(xué)生”:class_id = 2,再加上NOT:NOT class_id = 2:
SELECT * FROM students WHERE?NOT class_id = 2;
要組合三個(gè)或者更多的條件,就需要用小括號(hào)()表示如何進(jìn)行條件運(yùn)算。例如,編寫一個(gè)復(fù)雜的條件:分?jǐn)?shù)在80以下或者90以上,并且是男生:
SELECT * FROM students WHERE (score <80 OR score>90) AND gender = 'M';
如果不加括號(hào),條件運(yùn)算按照NOT、AND、OR的優(yōu)先級(jí)進(jìn)行,即NOT優(yōu)先級(jí)最高,其次是AND,最后是OR。加上括號(hào)可以改變優(yōu)先級(jí)。
通過WHERE條件查詢,可以篩選出符合指定條件的記錄,而不是整個(gè)表的所有記錄。
3. 投影查詢
如果我們只希望返回某些列的數(shù)據(jù),而不是所有列的數(shù)據(jù),我們可以用SELECT 列1, 列2, 列3 FROM ...,讓結(jié)果集僅包含指定列。這種操作稱為投影查詢。
例如,從students表中返回id、score和name這三列:
SELECT id, score, name FROM students;
4.排序
我們使用SELECT查詢時(shí),查詢結(jié)果集通常是按照id排序的,也就是根據(jù)主鍵排序。這也是大部分?jǐn)?shù)據(jù)庫的做法。如果我們要根據(jù)其他條件排序怎么辦?可以加上ORDER BY子句。例如按照成績從低到高進(jìn)行排序:
SELECT id, score, name FROM students ORDER BY score;
如果要反過來,按照成績從高到底排序,我們可以加上DESC表示“倒序”:
SELECT id, score, name FROM students ORDER BY score DESC;
SELECT查詢不但可以從一張表查詢數(shù)據(jù),還可以從多張表同時(shí)查詢數(shù)據(jù)。查詢多張表的語法是:SELECT * FROM <表1> <表2>。
5. 連接查詢
內(nèi)連接(INNER JOIN)
外連接(OUTER JOIN)?
左連接(LEFT OUTER JOIN)
右連接(RIGHT OUTER JOIN)
全連接(FULL OUTER JOIN)

參考資料