關(guān)系型數(shù)據(jù)庫(kù)和SQL
- SQL語(yǔ)言的三個(gè)部分
- DML:Data Manipulation Language,數(shù)據(jù)操縱語(yǔ)言,檢索、修改、增加、刪除數(shù)據(jù)庫(kù)(表)中的數(shù)據(jù)
- DDL:Data Definition Language,數(shù)據(jù)定義語(yǔ)言,創(chuàng)建和修改數(shù)據(jù)庫(kù)(表)本身
- DCL:Data Control Language,維護(hù)數(shù)據(jù)庫(kù)安全
- 關(guān)系型數(shù)據(jù)庫(kù)基本術(shù)語(yǔ)
- relational(關(guān)系):表示各表彼此關(guān)聯(lián)
- record(記錄):表中的行(row)
- field(字段):表中的列(column)
- primary key:表的主鍵,通常為自增型(auto-increment),本身沒(méi)有特殊含義,只用于保證每一行都有一個(gè)唯一的值
- foreign key:表的外鍵,確保這一列有一個(gè)有效的值,通常會(huì)把某個(gè)其他表的共同列,通常是主鍵作為外鍵,比如訂單表中的客戶(hù)列
- column(field)的數(shù)據(jù)類(lèi)型(更詳細(xì)的數(shù)據(jù)類(lèi)型介紹參見(jiàn)SQL數(shù)據(jù)類(lèi)型)
- 數(shù)字
- bit:位,只允許0和1
- integer:整數(shù),不含小數(shù)位
- decimal:浮點(diǎn)數(shù),含小數(shù)位
- real number:實(shí)數(shù)
- 字符:string/character string類(lèi)型,在SQL語(yǔ)句中需要用引號(hào)括起來(lái)
- 日期/時(shí)間:用于表示日期和時(shí)間,在SQL語(yǔ)句中需要用引號(hào)括起來(lái),允許對(duì)所涉及的日期進(jìn)行特殊運(yùn)算
- NULL:空值,非數(shù)據(jù)類(lèi)型,而是在允許包含空值的列中表示空置
基本數(shù)據(jù)檢索
- SQL語(yǔ)句不區(qū)分大小寫(xiě),且可以寫(xiě)成任意多行
- 可以把重要關(guān)鍵字作為單獨(dú)一行凸顯語(yǔ)義
- 從表中選擇所有:
SELECT * FROM tablename - 指定列:
SELECT columnname FROM tablename - 指定多個(gè)列:
SELECT column1, column2 FROM tablename -
帶空格的列名:Microsoft SQL Server使用方括號(hào)
[],MySQL使用重音符`,Oracle使用雙引號(hào)
計(jì)算字段和別名
- 計(jì)算字段
- 直接量:與表中數(shù)據(jù)沒(méi)有任何關(guān)系的值叫做literal value(直接量),字符串直接量需要加引號(hào),數(shù)字直接量不需要
- 算數(shù)運(yùn)算:允許使用列數(shù)據(jù)與直接量或其它列數(shù)據(jù)進(jìn)行加減乘除運(yùn)算,比如
SELECT QuantityPurchased * PricePerItem FROM Orders - 連接字段:把字符數(shù)據(jù)連接或組合到一起,Microsoft SQL Server使用加號(hào)
+,MySQL使用CONCAT()函數(shù)連接字符串,Oracle使用雙豎線(xiàn)||
- 別名
- 列的別名:用于修改列(表頭)標(biāo)題或?yàn)橛?jì)算字段提供列(表頭)標(biāo)題,比如
SELECT f_n AS 'first_name' from customers - 表的別名:通常有三種情況需要修改表名稱(chēng),a.不好理解或復(fù)雜的表名,b.從多個(gè)表中進(jìn)行選擇,c.使用子查詢(xún);
SELECE something from someshittablename AS another_table_name
- 列的別名:用于修改列(表頭)標(biāo)題或?yàn)橛?jì)算字段提供列(表頭)標(biāo)題,比如
使用函數(shù)
- Scalar function:標(biāo)量函數(shù),針對(duì)單行中的數(shù)據(jù)執(zhí)行
- Aggregate function:聚合函數(shù),針對(duì)較大的數(shù)據(jù)集合進(jìn)行操作
- 字符函數(shù)
-
LEFT/RIGHT (string, numberOfCharactors):從左/右取字符串?dāng)?shù)據(jù)的指定位數(shù),在Oracle中以SUBSTR替代 -
SUBSTRING (string, start, end):取得字符串?dāng)?shù)據(jù)的子字符串,在Oracle中以SUBSTR替代 -
LTRIM/RTRIM (string):刪除字符串?dāng)?shù)據(jù)左側(cè)/右側(cè)的空格 -
CONCAT (string1, string2, string3 ...):拼接多個(gè)字符串,Oracle中只允許拼接兩個(gè)字符串 -
UPPER/LOWER (string):返回字符串的大/小寫(xiě)
-
- 復(fù)合函數(shù):函數(shù)的嵌套使用被稱(chēng)為復(fù)合函數(shù),比如
RIGHT(RTRIM(something)) AS 'something' - 日期時(shí)間函數(shù)
-
GETDATE/NOW/CURRENT_DATE ():三個(gè)函數(shù)都用于獲取當(dāng)前時(shí)間,對(duì)應(yīng)Microsoft SQL Server/MySql/Oracle三家數(shù)據(jù)庫(kù)的實(shí)現(xiàn) -
DATEPART (date_part, date_value):?jiǎn)为?dú)返回某個(gè)部分的時(shí)間,date_part為需要返回的時(shí)間部分,date_value為原始時(shí)間,MySQL的實(shí)現(xiàn)為DATE_FORMAT(date_value, date_format),date_value為原始時(shí)間,date_format為類(lèi)似于%d這樣的格式用于告訴函數(shù)需要返回哪部分時(shí)間,date_part的有效值為:year/quarter/month/dayofyear/day/month/hour/minute/second -
DATEDIFF (date_part, start_date, end_date):用于計(jì)算任意兩個(gè)不同日期間相差的時(shí)間,在MySQL中該函數(shù)之允許計(jì)算天數(shù)差異,所以date_part參數(shù)不可用,僅需要傳入兩個(gè)日期即可
-
- 數(shù)值函數(shù)(數(shù)學(xué)函數(shù))
-
ROUND (NumbericValue, DecimalPlaces):對(duì)任意數(shù)進(jìn)行四舍五入,NumbericValue表示要四舍五入的數(shù),DecimalPlaces表示從第幾位開(kāi)始四舍五入(即需要保留到第幾位),以十分位為0,向左為負(fù)數(shù),向右為正數(shù) -
RAND ([seed]):產(chǎn)生一個(gè)隨機(jī)數(shù) ,可選的seed參數(shù)為一個(gè)整數(shù),用于每次返回相同的值 -
PI ():返回?cái)?shù)學(xué)運(yùn)算中的pi值
-
- 轉(zhuǎn)換函數(shù)
-
CAST (expression AS data_type):將數(shù)據(jù)從一種類(lèi)型轉(zhuǎn)換為另一種類(lèi)型,expression表示數(shù)據(jù)或函數(shù)表達(dá)式,data_type表示需要轉(zhuǎn)換到的數(shù)據(jù)類(lèi)型,一般情況下SQL在做計(jì)算時(shí)會(huì)進(jìn)行自動(dòng)的類(lèi)型轉(zhuǎn)換,所以很少用到這個(gè)函數(shù),它的典型使用場(chǎng)景是當(dāng)一個(gè)日期被保存成了字符串,需要轉(zhuǎn)換為真正的日期數(shù)據(jù):CAST('2017-5-1', AS DATETIME),Oracle中該函數(shù)的參數(shù)形式會(huì)不一樣 -
ISNULL/IFNULL/NVL (column_data_maybe_null, if_null_will_use_this_data ):將NULL值轉(zhuǎn)換為一個(gè)有意義的值,對(duì)應(yīng)Microsoft SQL Server/MySql/Oracle三家數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
-
排序數(shù)據(jù)
排序數(shù)據(jù)的語(yǔ)法如下:
SELECT
column1,
column2
FROM table1, table2
ORDER BY column3, column2 DESC
-
ORDER BY句子總是在FROM子句之后,FROM子句總是在SELECT關(guān)鍵字之后 -
SELECT和ORDER BY后面指定的列,可能是完全不同的一些列 - 使用關(guān)鍵字
ASC和DESC來(lái)升序/降序排列 -
ORDER BY后指定了多列,則首先按照第一列排序,如遇相同則相同的行按第二列排序,以此類(lèi)推 - 根據(jù)計(jì)算字段排序時(shí),如果計(jì)算字段已經(jīng)出現(xiàn)在
SELECT關(guān)鍵字后,則只需要在ORDER BY子句中指定計(jì)算字段的別名即可(經(jīng)測(cè)試在MySQL中如果計(jì)算字段別名帶有空格則暫時(shí)無(wú)法在此引用,因?yàn)椴荒苁褂靡?hào)),如果計(jì)算字段沒(méi)有出現(xiàn)在SELECT關(guān)鍵字后,則可直接在ORDER BY子句中指定一個(gè)計(jì)算字段,例如:SELECT title, rental_duration, rental_rate FROM film ORDER BY rental_duration * rental_rate DESC - 按升序排列時(shí),大部分的SQL數(shù)據(jù)庫(kù)都會(huì)是按
NULL(Oracle中排在最后,可使用NULLS FIRST關(guān)鍵字來(lái)強(qiáng)制最先)-數(shù)字-字符(字符中首先顯示數(shù)字字符,再顯示普通字符,除Oracle外不區(qū)分大小寫(xiě))來(lái)進(jìn)行排序,反之亦然。
基于列的邏輯
- 基于列的邏輯主要用于根據(jù)邏輯條件改變想要展現(xiàn)給用戶(hù)的輸出
- 簡(jiǎn)單格式:判斷某列的值為某個(gè)具體值后將其轉(zhuǎn)換為一個(gè)其它值
SELECT column1, column2
CASE column3
WHEN value1 THEN result1
WHEN value2 THEN value2
(repeat WHEN-THEN any number of times)
[ELSE defaul_result]
END
column4
FROM tablename
- 查詢(xún)格式:判斷一列或多列中的某個(gè)值是否符合某個(gè)條件而將其轉(zhuǎn)換為一個(gè)其它值并顯示在一列中
SELECT
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
(repeat WHEN-THEN any number of times)
[ELSE defaul_result]
END AS custom_column_name,
FROM tablename
# 最新版的MySQL語(yǔ)法與書(shū)中的語(yǔ)法有細(xì)微差別:
# ELSE子句最后不需要逗號(hào)
SELECT
title,
CASE
WHEN rental_duration = 3 THEN 'Three Day Left'
WHEN rental_rate = 0.99 THEN 'Cheapest'
ELSE 'Normal'
END AS 'Rental Status'
FROM film
基于行的邏輯
- 基于行的邏輯主要用于獲取滿(mǎn)足特定條件的數(shù)據(jù)
- 應(yīng)用查詢(xún)條件
- SQL中的查詢(xún)條件從
WHERE子句開(kāi)始 -
WHERE子句總是在FROM和ORDER BY子句之間,實(shí)際上任何“子句”都必須按照這個(gè)順序來(lái)SELECT columnList FROM tableList WHERE condition ORDER BY columnList
- SQL中的查詢(xún)條件從
-
WHERE子句操作符,以下這些操作符都可以在基于列的邏輯CASE WHEN condition語(yǔ)句中使用- 等于:
= - 不等于:
<> - 大于:
> - 小于:
< - 大于等于:
>= - 小于等于:
<=
SELECT first_name, last_name FROM actor WHERE age > 18 - 等于:
- 限制行
- 使用
TOP/LIMIT/ROWNUM(對(duì)應(yīng)Microsoft SQL Server、MySQL和Oracle)限制行數(shù)(關(guān)鍵字TOP返回的行,并不是真的隨機(jī)樣本,而是根據(jù)數(shù)據(jù)庫(kù)中的物理存儲(chǔ)方式限定了前幾行數(shù)據(jù)而已)# Microsoft SQL Server SELECT TOP number columnList FROM table # MySQL SELECT columnList FROM table LIMIT number # Oracle SELECT columnList FROM table WHERE ROWNUM <= number - 結(jié)合
SORT BY子句做“Top N”查詢(xún)(基于特定分類(lèi),得到帶有最大/小值的一定數(shù)量的行)# 本月賣(mài)得最好的莎士比亞的三本書(shū) # MySQL SELECT title AS 'Book Title', current_month_sale AS 'Quantity Sold' FROM books WHERE author = 'Shakespear' LIMIT 3 ORDER BY current_month_sale DESC # Oracle中的TOP N查詢(xún)需要用到子查詢(xún),后文會(huì)細(xì)講 SELECT * FROM (SELECT title AS 'Book Title', current_month_sale AS 'Quantity Sold' FROM books ORDER BY current_month_sale) WHERE ROWNUM <= 3
- 使用
布爾邏輯(更復(fù)雜的基于行的邏輯)
- 使用與
AND、或OR、非NOT三個(gè)關(guān)鍵字在WHERE子句中表示布爾邏輯。與其它語(yǔ)言的計(jì)算順序一樣,AND的優(yōu)先級(jí)最高,OR其次,NOT優(yōu)先級(jí)最低,也可以使用()來(lái)改變?nèi)叩挠?jì)算順序# 這個(gè)例子僅為展示布爾邏輯,實(shí)際使用不應(yīng)該這么繞 SELECT first_name, last_name, age FROM actors WHERE NOT( (age < 18 OR age > 60) AND last_name = 'Jhon' ) - 還有兩個(gè)表示范圍的操作符
BETWEEN和IN,用于替代column >= range_bottom AND column <= range_top和column = value1 OR column = value2這樣的特例,簡(jiǎn)化SQL語(yǔ)句的編寫(xiě)# BETWEEN,等價(jià)于 age >= 18 AND age <= 60 SELECT first_name, last_name, age FROM actors WHERE age BETWEEN 18 AND 60 # IN,等價(jià)于 state = 'IL' AND state = 'NY' SELECT customer_name, state FROM orders WHERE state IN ('IL', 'NY') - 使用
IS NULL在WHERE子句中判斷一個(gè)列是否為空,也可以與函數(shù)ISNULL(column, value)結(jié)合使用# 選取重量為0或者沒(méi)有填寫(xiě)重量的產(chǎn)品 SELECT product_description, weight FROM products WHERE weight = 0 OR weight IS NULL # 使用ISNULL等價(jià)的寫(xiě)法 SELECE product_description, weight FROM products WHERE ISNULL(weight, 0) = 0 # IS NULL和ISNULL SELECT product_description, ISNULL(weight, 0) AS 'weight' FROM products WHERE weight = 0 OR weight IS NULL
模糊匹配
-
WHERE子句可以使用LIKE操作符來(lái)查找針對(duì)列值的某部分匹配- 包含某關(guān)鍵字:
SELECT title FROM film WHERE title LIKE '%love%' - 以某關(guān)鍵字開(kāi)頭:
SELECT title FROM film WHERE title LIKE 'love%' - 以某關(guān)鍵字結(jié)尾
SELECT title FROM film WHERE title LIKE '%love' - 包含某關(guān)鍵字但不以其開(kāi)頭也不以其結(jié)尾(未能在MySQL 4中驗(yàn)證,只驗(yàn)證通過(guò)了單獨(dú)的不以某字符串開(kāi)頭,或者不以某字符串結(jié)尾兩種情況)
SELECT title FROM film WHERE title LIKE '% love %'
- 包含某關(guān)鍵字:
-
通配符符號(hào) 含義 % 任意個(gè)任意字符 _ 一個(gè)任意字符 [characterlist] 一個(gè)指定字符列表中的字符(在MySQL和Oracle中沒(méi)有) [^charactorlist] 一個(gè)非指定字符列表中的字符(在MySQL和Oracle中沒(méi)有) 符號(hào) 含義 % 任意個(gè)任意字符 _ 一個(gè)任意字符 [characterlist] 一個(gè)指定字符列表中的字符(在MySQL和Oracle中沒(méi)有) [^charactorlist] 一個(gè)非指定字符列表中的字符(在MySQL和Oracle中沒(méi)有) -
NOT操作符可以和LIKE操作符組合使用,例如SELECT first_name, last_name FROM actor WHERE first_name LIKE '%ARY%' AND last_name NOT LIKE '[MG]ARY' - 按照讀音匹配(不常用也不好用)
-
SOUNDEX函數(shù):能夠輸出一個(gè)表示字符讀音的四字代碼(以首字母開(kāi)頭,然后刪去剩余字符中所有元音和字母y,最后轉(zhuǎn)換為一個(gè)三位數(shù)的數(shù)字用于表示讀音,最后輸出類(lèi)似S530) -
DIFFERENCE函數(shù):可以和SOUNDEX函數(shù)一起使用(僅Microsoft SQL Server支持),檢查兩個(gè)字符的SOUNDEX相似度并返回一個(gè)表示讀音相近度的數(shù)字,(兩個(gè)字符的SOUNDEX值共有四個(gè)字符,每有一個(gè)位置的字符相等,則結(jié)果自增1,所以DIFFERENCE函數(shù)的返回值只有0到4五個(gè)可能的數(shù)字,越大越相近,越小越不同
-
匯總數(shù)據(jù)
- 消除重復(fù):使用
DISTINCT關(guān)鍵字來(lái)刪除輸出重復(fù)的行# 查看所有藝術(shù)家(沒(méi)有顯示相同藝術(shù)家的行) SELECT DISTINCT artist FROM songs ORDER BY artist # 查看所有藝術(shù)家和專(zhuān)輯的唯一組合(沒(méi)有顯示同一藝術(shù)家和同一專(zhuān)輯的行,每一行中藝術(shù)家和專(zhuān)輯的組合是唯一的) SELECT DISTINCT artist, album FROM songs ORDER BY artist, album -
聚合函數(shù):標(biāo)量函數(shù)只能針對(duì)單個(gè)的數(shù)字或值進(jìn)行計(jì)算,而聚合函數(shù)則可以用于分組數(shù)據(jù)函數(shù) 解釋 SUM合計(jì)、加總 AVG平均值 MIN最小值 MAX最大值 COUNT數(shù)量 函數(shù) 解釋 SUM合計(jì)、加總 AVG平均值 MIN最小值 MAX最大值 COUNT數(shù)量 # 總值、均值、最大值、最小值 SELECT SUN(fee) AS 'Total Gym Fees' AVG(grade) AS 'Average Quiz Score' MIN(grade) AS 'Minimum Quiz Score' MAX(grade) AS 'Maximum Quiz Score' FROM grades WHERE grade_type = 'quiz' # 返回所有選中行的數(shù)目 SELECT COUNT(*) AS 'Count of Homework Rows' FROM grades WHERE grade_type = 'homework' # 返回指定列中存在值的行的數(shù)目 SELECT COUNT(grade) AS 'Count of Homework Rows' FROM grades WHERE grade_type = 'homework' # 與DISTINCT配合返回指定列中唯一值的行數(shù) SELECT COUNT(DISTINCT fee_type) AS 'Number of Fee Types' FROM Fees - 分組數(shù)據(jù):以指定列為依據(jù)對(duì)所有選中行進(jìn)行分組,重新劃分了行的顯示規(guī)則
- 單列分組
# 統(tǒng)計(jì)每個(gè)分級(jí)下的電影數(shù)量 SELECT rating, COUNT(rating) AS 'Rating Count' FROM film GROUP BY rating - columnlist中的所有列,要么是
GROUP BY子句中的列,要么是在聚合函數(shù)中使用的列,因?yàn)樗袃?nèi)容都在組中出現(xiàn),不在組中的內(nèi)容沒(méi)有辦法處理,這種情況下MySQL與其它兩種數(shù)據(jù)庫(kù)不同,它只會(huì)得出錯(cuò)誤的結(jié)果,而不會(huì)報(bào)錯(cuò) - 多列分組:組的概念可以擴(kuò)展,從而根據(jù)多列進(jìn)行分組
# 統(tǒng)計(jì)不同租金率下的不同分級(jí)電影的數(shù)量 SELECT rating, rental_rate, COUNT(rating) AS 'Rating Count' FROM film GROUP BY rating, rental_rate - 在沒(méi)有分組的情況下,聚合函數(shù)(
SUM、AVG、MIN、MAX、COUNT)統(tǒng)計(jì)的是所有行的數(shù)據(jù),在有分組的情況下,這些聚合函數(shù)則僅會(huì)統(tǒng)計(jì)組內(nèi)的數(shù)據(jù),當(dāng)然實(shí)際上也是最終顯示的表的每一行的聚合 -
GROUP BY子句中的columnlist順序沒(méi)有意義,但ORDER BY子句中的順序是有意義的,一般按照排序的優(yōu)先順序來(lái)列出這些列會(huì)很有幫助(也即SELECT中的columnlist與ORDER BY中的columnlist保持一致)
- 單列分組
- 基于分組應(yīng)用查詢(xún)條件:
WHERE子句中的查詢(xún)條件是針對(duì)單獨(dú)的行來(lái)應(yīng)用的,如果存在GROUP BY分組,就需要使用HAVING關(guān)鍵字了# 查看分級(jí)中所有電影平均時(shí)長(zhǎng)大于100分鐘的分級(jí)中電影的數(shù)量 SELECT rating AS '分級(jí)', COUNT(title) AS '電影數(shù)量', AVG(length) AS '平均時(shí)長(zhǎng)' FROM film GROUP BY rating HAVING AVG(length) > 100 ORDER BY 電影數(shù)量 DESC - 至此,
SELECT語(yǔ)句的一般格式如下:SELECT columnlist FROM tablelist WHERE condition GROUP BY columnlist HAVING condition ORDER BY COLUMNLIST
用內(nèi)連接來(lái)組合表
- 關(guān)系型數(shù)據(jù)庫(kù)最重要的成就是能夠把數(shù)據(jù)組織到任意多個(gè)相互關(guān)聯(lián)的表中,但同時(shí)這些又是彼此獨(dú)立的;人們可以分析業(yè)務(wù)實(shí)體然后進(jìn)行適當(dāng)?shù)臄?shù)據(jù)庫(kù)設(shè)計(jì),這樣就可以具有最大的靈活性;關(guān)系型數(shù)據(jù)庫(kù)可以以任何你想要的方式把代表業(yè)務(wù)實(shí)體的表連接到一起,從而實(shí)現(xiàn)“關(guān)系”
-
類(lèi)似“客戶(hù)”和“訂單”這樣兩個(gè)獨(dú)立的實(shí)體信息,至少應(yīng)該要拆分到兩個(gè)表中(訂單表很有可能需要繼續(xù)拆分成多個(gè)表),可以使用實(shí)體關(guān)系圖(entity-relationship diagram)來(lái)表示可視化地表示兩個(gè)表以及他們之間存在的隱性關(guān)系,實(shí)體(entity)指的是表,關(guān)系(relationship)指的是這些表中數(shù)據(jù)元素之間所畫(huà)的線(xiàn)
實(shí)體關(guān)系圖 - 內(nèi)連接
- 使用關(guān)鍵字
INNER JOIN來(lái)指定想要連接的第二個(gè)表,使用ON來(lái)指定兩個(gè)表的共同列由于共同列名稱(chēng)是一樣的,所以需要在列名前面使用表名作為命名空間來(lái)區(qū)分兩個(gè)表中獨(dú)立的列# 簡(jiǎn)單地依據(jù)customer_id將顧客表和訂單表拼接到一個(gè)表中 SELECT * FROM customers INNER JOIN orders ON customers.customer_id = orders.customer_id - 內(nèi)連接只會(huì)返回關(guān)聯(lián)的兩個(gè)表之間相匹配的數(shù)據(jù),表在
FROM和INNER JOIN之間的順序僅會(huì)影響哪個(gè)表的列先顯示,不會(huì)影響行的順序 - SQL不是過(guò)程式語(yǔ)言,不會(huì)指定任務(wù)的先后順序,而只是指定需要的邏輯并讓數(shù)據(jù)庫(kù)內(nèi)部機(jī)制去決定如何執(zhí)行任務(wù)。
- 僅使用
FROM和WHERE也可以指定表的內(nèi)連接,這是內(nèi)連接的另一種范式,但因其沒(méi)有顯示地表示出連接的邏輯,所以不推薦使用(所以其實(shí)INNER JOIN ON的唯一作用僅僅是表達(dá)語(yǔ)義而已)SELECT * FROM customers, orders WHERE customers.customer_id = orders.customer_id - 可以通過(guò)顯式地指定表的別名和列的別名(注意Oracle中表的別名與其他兩個(gè)庫(kù)的區(qū)別,前文有提及),來(lái)去除內(nèi)連接后的重復(fù)列或者只顯示需要的列,這是推薦的做法:
SELECT c.customer_id AS 'Customer Id', c.first_name AS 'First Name', c.last_name AS 'Last Name', o.order_id AS 'Order Id', o.quantity AS 'Quantity', o.price_per_item AS 'Price' FROM customers AS 'c', INNER JOIN
- 使用關(guān)鍵字
用外連接來(lái)組合表
- SQL中表連接的默認(rèn)類(lèi)型就是內(nèi)連接,所以可以只使用
JOIN來(lái)指定一個(gè)內(nèi)連接 - 外連接有三種類(lèi)型:左連接
LEFT OUTER JOIN,右連接RIGHT OUTER JOIN,全連接FULL OUTER JOIN,其中關(guān)鍵字OUTER并不是必須的。 -
所以總結(jié)起來(lái)有4種類(lèi)型的連接:連接類(lèi)型 全稱(chēng) 簡(jiǎn)寫(xiě) 用途 內(nèi)連接 INNER JOINJOIN兩個(gè)表都是主表(primary table),共同列中所有的行都必須同時(shí)在這兩個(gè)表中才會(huì)被選中 左連接 LEFT OUTER JOINLEFT JOIN左表為主表,右表為從表(secondary table),選中共同列中所有在主表中的行,不管它是否出現(xiàn)在從表 右連接 RIGHT OUTER JOINRIGHT JOIN左表為從表,右表為主表,規(guī)則同左連接 全連接 FULL OUTER JOINFULL JOIN兩個(gè)表都是從表,共同列中的行只要出現(xiàn)在任意一個(gè)表中都會(huì)被選中 連接類(lèi)型 全稱(chēng) 簡(jiǎn)寫(xiě) 用途 內(nèi)連接 INNER JOINJOIN兩個(gè)表都是主表(primary table),共同列中所有的行都必須同時(shí)在這兩個(gè)表中才會(huì)被選中 左連接 LEFT OUTER JOINLEFT JOIN左表為主表,右表為從表(secondary table),選中共同列中所有在主表中的行,不管它是否出現(xiàn)在從表 右連接 RIGHT OUTER JOINRIGHT JOIN左表為從表,右表為主表,規(guī)則同左連接 全連接 FULL OUTER JOINFULL JOIN兩個(gè)表都是從表,共同列中的行只要出現(xiàn)在任意一個(gè)表中都會(huì)被選中 - 在實(shí)體關(guān)系圖中,單向箭頭表示表之間的連接是單向的,箭頭終點(diǎn)的表中有一列所有行都能在箭頭起點(diǎn)的表中找到,但反過(guò)來(lái)則不一定,比如,不是所有的客戶(hù)都有訂單,且一個(gè)客戶(hù)可能有多個(gè)訂單,但所有的訂單都會(huì)有客戶(hù)信息(甚至可以說(shuō)所有的訂單有且只有一個(gè)客戶(hù)信息),退貨信息與訂單的關(guān)系類(lèi)似
- 當(dāng)連接主表和從表時(shí),我們需要主表中所有的行,即使在從表中的共同列沒(méi)有任何行與之匹配
- 使用
IS NOT NULL和IS NULL來(lái)過(guò)濾空行或顯示空行# 過(guò)濾了沒(méi)有訂單的客戶(hù)和有退貨的訂單 SELECT customers.first_name AS 'First Name', customers.last_name AS 'Last Name', orders.order_date AS 'Order Date', orders.order_amount AS 'Order Amt' FROM customers LEFT JOIN orders ON orders.customer_id = customers.customre_id LEFT JOIN refunds ON orders.order_id = refunds.order_id WHERE orders.order_id IS NOT NULL AND refunds.refund_id IS NULL ORDER BY customers.customer_id, orders.order_id - 右連接與左連接唯一的不同就是主從表在關(guān)鍵字前后的位置,所以基本上沒(méi)有必要使用右連接,建議只使用左連接,因?yàn)槿酥庇X(jué)上往往認(rèn)為先列出的表更為重要
- 當(dāng)設(shè)計(jì)有多個(gè)表的復(fù)雜
FROM子句時(shí),建議僅使用關(guān)鍵字LEFT JOIN并且避免使用圓括號(hào) - 全連接會(huì)顯示所有行,即使沒(méi)有在其他表中找到任何一個(gè)匹配。但在實(shí)際工作中很少會(huì)用到全連接,因?yàn)楸碇g的這種類(lèi)型的關(guān)系是非常少見(jiàn)的。
自連接和視圖
- 自連接:處理那些本質(zhì)上是自引用的表(表中的一列指向自己的另一列,比如員工表中的manager列指向自己的employee_id,員工的經(jīng)理也是員工),為其創(chuàng)建多個(gè)視圖
- 可以使用四種表連接中的任意一種來(lái)實(shí)現(xiàn)自連接,唯二的區(qū)別就是
ON子句中,非自連接的共同列來(lái)自?xún)蓚€(gè)表,自連接的共同列來(lái)自同一個(gè)表,所以這時(shí)候需要在FROM關(guān)鍵字和JOIN關(guān)鍵字后為該表各自創(chuàng)建一個(gè)別名用以在ON子句中進(jìn)行區(qū)分
# 列出personnel表中所有員工的經(jīng)理名字 SELECT employees.employee_name AS 'Employee Name', managers.employee_name AS 'Maneger Name' FROM personnel AS 'employees' LEFT JOIN personnel AS 'managers' ON employees.manager_id = managers._employee_id ORDER BY employee.employee_id - 可以使用四種表連接中的任意一種來(lái)實(shí)現(xiàn)自連接,唯二的區(qū)別就是
- 視圖
- 視圖只是保存在數(shù)據(jù)庫(kù)中的
SELECT語(yǔ)句,它不包含任何數(shù)據(jù)。 - 隨著時(shí)間的流逝,訪(fǎng)問(wèn)數(shù)據(jù)的需求會(huì)有所變化,但有時(shí)很難去重新組織數(shù)據(jù)庫(kù)中的數(shù)據(jù)以滿(mǎn)足新的需求。視圖允許為數(shù)據(jù)庫(kù)中已經(jīng)存在的數(shù)據(jù)創(chuàng)建新的虛擬視圖(或理解為虛擬的表)而無(wú)需重新組織數(shù)據(jù),這為我們?cè)黾恿耸冀K能保持?jǐn)?shù)據(jù)庫(kù)設(shè)計(jì)不斷更新的能力。
- 因?yàn)橐晥D沒(méi)有保存物理數(shù)據(jù),所以在視圖中不能包含
ORDER BY子句
- 視圖只是保存在數(shù)據(jù)庫(kù)中的
- 創(chuàng)建視圖
# 創(chuàng)建視圖的語(yǔ)法: CREATE VIEW view_name AS select_statement # 一個(gè)創(chuàng)建視圖的例子,注意不能有ORDER BY子句 CREATE VIEW customers_orders_refunds AS SELECT customers.first_name AS 'First Name', customers.last_name AS 'Last Name', orders.order_date AS 'Order Date', orders.order_amount AS 'Order Amt' FROM customers LEFT JOIN orders ON orders.customer_id = customers.customre_id LEFT JOIN refunds ON orders.order_id = refunds.order_id WHERE orders.order_id IS NOT NULL AND refunds.refund_id IS NULL - 引用視圖
# 創(chuàng)建視圖 CREATE VIEW view_name AS select_statement # 引用視圖 SELECT * from view_name- 當(dāng)引用視圖中的列的時(shí)候,需要指定列的別名,而列的別名是在創(chuàng)建視圖時(shí)指定的
# 創(chuàng)建視圖 CREATE VIEW customers_view AS SELECT first_name AS 'First Name', last_name AS 'Last Name' FROM customers # 引用視圖中的列 SELECT `First Name`, `Last Name`, FROM customers_view WHERE `Last Name` = 'Lopez'
- 當(dāng)引用視圖中的列的時(shí)候,需要指定列的別名,而列的別名是在創(chuàng)建視圖時(shí)指定的
- 視圖的優(yōu)點(diǎn)
- 視圖可以減少?gòu)?fù)雜度:將復(fù)雜的
SELECT語(yǔ)句封裝為一個(gè)視圖 - 視圖可以增加復(fù)用性:封裝那些總是相連的表
- 視圖可以正確地格式化數(shù)據(jù):如果一個(gè)表中的某些數(shù)據(jù)總是需要格式化,可以將其封裝到視圖中
- 視圖可以創(chuàng)建計(jì)算的列:如果需要一個(gè)含有大量的計(jì)算字段的表,也可將其封裝到視圖中
- 視圖可以用來(lái)重新命名列的名稱(chēng):如果一個(gè)表中的列名總是需要重命名,可以將其封裝到視圖中
- 視圖可以創(chuàng)建數(shù)據(jù)子集:如果總是只需要看到某個(gè)表的某些子集,可以將它們封裝到不同的視圖
- 視圖可以用來(lái)加強(qiáng)安全性限制:如果一個(gè)表中的某些數(shù)據(jù)希望對(duì)某些用戶(hù)做訪(fǎng)問(wèn)限制,可以使用視圖將它們挑出來(lái)然后僅將視圖的權(quán)限給那些用戶(hù)而不是整個(gè)表的權(quán)限
- 視圖可以減少?gòu)?fù)雜度:將復(fù)雜的
- 修改視圖:使用
ALTER關(guān)鍵字修改一個(gè)已經(jīng)創(chuàng)建的視圖,重新指定被封裝到其中的SELECT語(yǔ)句# 整個(gè)被封裝到視圖的select語(yǔ)句都需要重新指定 ALTER VIEW view_name AS new_select_statement # 與Microsoft SQL Server和MySQL不同,Oracle在修改視圖之前,需要使用DROP VIEW view_name先刪除視圖- 同樣,修改視圖與創(chuàng)建視圖一樣,只是修改了視圖的定義,它本身不會(huì)返回任何數(shù)據(jù)
- 刪除視圖:使用
DROP VIEW view_name來(lái)刪除視圖
子查詢(xún)
- 包含在其他查詢(xún)中的查詢(xún)叫做子查詢(xún),子查詢(xún)可以用在
SELECT、INSERT、UPDATE、DELETE語(yǔ)句 - 在
SELECT語(yǔ)句中子查詢(xún)可以有三種用法:- 一個(gè)一般的
SELECT語(yǔ)句格式如下:SELECT column_list FROM table_list WHERE condition GROUP BY column_list HAVING condition ORDER BY column_list - 當(dāng)子查詢(xún)是
table_list的一部分時(shí),它指定了一個(gè)數(shù)據(jù)源 - 當(dāng)子查詢(xún)時(shí)
condition的一部分時(shí),它成為查詢(xún)條件的一部分 - 當(dāng)子查詢(xún)是
column_list的一部分時(shí),它創(chuàng)建了一個(gè)單個(gè)的計(jì)算的列
- 一個(gè)一般的
- 使用子查詢(xún)指定數(shù)據(jù)源:把一個(gè)子查詢(xún)指定為
FROM子句的一部分時(shí),它立即創(chuàng)建了一個(gè)新的數(shù)據(jù)源,并被當(dāng)做一個(gè)獨(dú)立的表或視圖來(lái)引用,與視圖的區(qū)別是視圖是永久保存在數(shù)據(jù)庫(kù)中的,而子查詢(xún)只是臨時(shí)的# 使用子查詢(xún)指定數(shù)據(jù)源的一般格式 SELECT column_list FROM [table_list] [JOIN] subquery AS custom_subquery_name # 從address表,city表和country表中列出五個(gè)地址對(duì)應(yīng)的城市和國(guó)家 SELECT address AS 'Address', city AS 'City', country AS 'Country' FROM address LEFT JOIN( SELECT city.city, city.city_id, country.country, country.country_id FROM city LEFT JOIN country ON city.country_id = country.country_id ) AS city_and_country ON address.city_id = city_and_country.city_id ORDER BY address LIMIT 5 - 使用子查詢(xún)指定查詢(xún)條件:把一個(gè)子查詢(xún)指定為
WHERE子句中IN操作符的右值,可以以更復(fù)雜的邏輯來(lái)為IN操作符創(chuàng)建一個(gè)可選列表;注意,當(dāng)子查詢(xún)用于指定查詢(xún)條件時(shí),僅能返回單一的列# 使用子查詢(xún)指定查詢(xún)條件的一般格式 SELECT column_list FROM table_list WHERE column IN subquery SELECT column_list FROM table_list WHERE subquery match_some_comdition # 列出所有使用現(xiàn)金支付的客戶(hù)名稱(chēng) SEELCT customer_name AS 'Customer Name' FROM costomers WHERE customer_id IN ( SELECT customer_id FROM orders WHERE order_type = 'cash' ) # 列出訂單金額少于20美元的客戶(hù)列表 SELECT customer_name AS 'Customer Name' FROM customers WHERE ( SELECT SUM(orderAmount) FROM orders WHERE customers.customer_id = orders.customer_id ) < 20 - 使用子查詢(xún)作為計(jì)算列:把一個(gè)子查詢(xún)作為column_list中的一項(xiàng),將其用作一個(gè)計(jì)算的列
# 使用子查詢(xún)作為計(jì)算列的一般格式 SELECT column_list, subquery_result AS 'Result Alia' FROM table_list # 查詢(xún)客戶(hù)及其訂單數(shù)量 SELECT customer_name AS 'Customer Name', ( SELECT COUNT(order_id) FROM orders WHERE customers.customer_id = orders.customer_id ) AS 'Number of Orders' FROM customers ORDER BY customers.customer_id - 關(guān)聯(lián)子查詢(xún):無(wú)法獨(dú)立運(yùn)行的子查詢(xún)?yōu)殛P(guān)聯(lián)子查詢(xún),可以獨(dú)立運(yùn)行的子查詢(xún)?yōu)榉顷P(guān)聯(lián)子查詢(xún)。非關(guān)聯(lián)子查詢(xún)完全獨(dú)立與外圍查詢(xún)語(yǔ)句,只會(huì)計(jì)算和執(zhí)行一次,而關(guān)聯(lián)子查詢(xún)需要針對(duì)返回的每一行逐行計(jì)算,且每次執(zhí)行子查詢(xún)的時(shí)候得到的結(jié)果可能都不一樣,上文中查詢(xún)客戶(hù)及其訂單數(shù)量中的子查詢(xún)即為關(guān)聯(lián)子查詢(xún),它使用了外圍查詢(xún)的數(shù)據(jù)來(lái)源
customers表 -
EXISTS操作符:用于確定一個(gè)關(guān)聯(lián)子查詢(xún)中是否存在數(shù)據(jù)# 查詢(xún)下過(guò)訂單的用戶(hù) SELECT customer_name AS 'Customer' FROM customers WHERE EXISTS ( SELECT * FROM orders WHERE customers.customer_id = orders.customer_id )
集合邏輯
在前文中,連接JOIN可以將來(lái)自?xún)蓚€(gè)表的列組合到一個(gè)表中,子查詢(xún)則是將一條SELECT語(yǔ)句的結(jié)果提供給第另一條SELECT語(yǔ)句使用。然而有時(shí)候我們希望將來(lái)自?xún)蓚€(gè)表的行組合到一個(gè)表中,這時(shí)候就需要使用SQL中的集合邏輯UNION,來(lái)做合并查詢(xún)。
-
UNION-合并兩條SELECT語(yǔ)句,選取在A或B中的數(shù)據(jù),如果同時(shí)存在在A或B中,僅顯示一條
使用SELECT order_date AS 'Date', 'order' AS 'Type', order_amount AS 'amount' FROM orders WHERE custom_id = 2 UNION SELECT return_date AS 'Date', 'return' AS 'type', return_amount AS 'amount' FROM returns WHERE custom_id = 2 ORDER BY dateUNION需要遵守3個(gè)規(guī)則(實(shí)際就一條規(guī)則:相同列):- 兩個(gè)
SELECT語(yǔ)句中的列的數(shù)量必須相等 - 兩個(gè)
SELECT語(yǔ)句中的列排列順序必須相同 - 兩個(gè)
SELECT語(yǔ)句中的列數(shù)據(jù)類(lèi)型必須相同
- 兩個(gè)
-
UNION ALL-合并兩條SELECT語(yǔ)句,選取在A或B中的數(shù)據(jù),即使同時(shí)存在在A或B中,都將顯示在結(jié)果中SELECT DISTINCT order_date AS 'Date' FROM orders UNION ALL SELECT DISTINCT return_date AS 'Date' FROM returns ORDER BY Date # UNION 確保來(lái)自?xún)蓚€(gè)表的行沒(méi)有重復(fù)數(shù)據(jù),但 UNION ALL 允許來(lái)自?xún)蓚€(gè)表的行可以有相同數(shù)據(jù) # DISTINCT 確保來(lái)自同一個(gè)表(或者說(shuō)同一個(gè)SELECT語(yǔ)句)的行沒(méi)有重復(fù)數(shù)據(jù) # 所以上面的語(yǔ)句選取的數(shù)據(jù)可能會(huì)存在重復(fù)數(shù)據(jù),但重復(fù)的數(shù)據(jù)并不來(lái)自?xún)蓚€(gè)表而是來(lái)自同一個(gè)表,并且僅會(huì)重復(fù)一次 -
INTERSECT-合并兩條SELECT語(yǔ)句,選取同時(shí)出現(xiàn)在A和B中的行(MySql不支持該操作符)SELECT order_date AS 'Date' FROM orders INTERSECT SELECT return_date As 'Date' FROM returns ORDER BY Date -
EXCEPT-合并兩條SELECT語(yǔ)句,選取僅出現(xiàn)在A或僅出現(xiàn)在B中的的數(shù)據(jù)(MySql和Oracle不支持該操作符,但Oracle提供了等價(jià)的MINUS操作符)SELECT order_date AS 'Date' FROM orders EXCEPT SELECT return_date AS 'Date' FROM returns ORDER BY Date
存儲(chǔ)過(guò)程和參數(shù)
到目前為止,前文所有的SQL語(yǔ)句都是單獨(dú)使用,然而很多時(shí)候,你會(huì)希望SQL語(yǔ)句能夠像函數(shù)一樣,定義一次,然后重復(fù)調(diào)用,并且可以使用參數(shù)來(lái)增加靈活性。這時(shí),你就可以使用存儲(chǔ)過(guò)程來(lái)實(shí)現(xiàn)這一目的。
- 創(chuàng)建存儲(chǔ)過(guò)程:創(chuàng)建存儲(chǔ)過(guò)程不會(huì)執(zhí)行任何內(nèi)容,只是直接創(chuàng)建了一個(gè)過(guò)程,以便后續(xù)執(zhí)行它。與表和視圖一樣,創(chuàng)建好的存儲(chǔ)過(guò)程在管理工具中是可以查看的
-- Microsoft SQL Server CREATE PROCEDURE ProcedureName (OptionalPrameterDeclarations) AS BEGIN SQLStatements END -- MySQL DELIMITER $$ -- 規(guī)定END語(yǔ)句使用的分隔符,默認(rèn)為分號(hào) CREATE PROCEDURE ProcedureName (OptionalPrameterDeclarations) BEGIN SQLStatements; -- 每一條SQL語(yǔ)句都必須使用分號(hào)分隔,即使只有一條 END$$ DELIMITER ; -- 將分隔符改回分號(hào) - 存儲(chǔ)過(guò)程的參數(shù):例如存儲(chǔ)一個(gè)選取特定用戶(hù)的SQL過(guò)程,可以使用參數(shù)來(lái)指定用戶(hù)的ID
-- Microsoft SQL Server CREATE PROCUDURE CustomerProcudure (@custId INT) AS BEGIN SELECT * FROM customers WHERE customer_id = @custId END -- MySQL DELIMITER $$ CREATE PROCEDURE CustomerProcudure (custId INT) BEGIN SELECT * FROM customers WHERE CUSTOMER_ID = custId; END DELEMITER ; - 執(zhí)行存儲(chǔ)過(guò)程
-- Microsoft SQL Server EXEC CustomerProcudure @custId = 2 -- MySQL CALL CustomerProcudure (2) - 修改和刪除存儲(chǔ)過(guò)程:在Microsoft SQL Server中,修改過(guò)程和創(chuàng)建過(guò)程幾乎一樣,只需要把
CREATE關(guān)鍵字替換為ALTER關(guān)鍵字即可;然而在MySQL中,雖然也存在ALTER命令,但它的功能十分簡(jiǎn)單,所以一般我們選擇先刪除存儲(chǔ)過(guò)程然后再重新創(chuàng)建-- 刪除存儲(chǔ)過(guò)程 DROP PROCEDURE ProcedureName - 函數(shù)與存儲(chǔ)過(guò)程的兩點(diǎn)區(qū)別
- 存儲(chǔ)過(guò)程可以有任意數(shù)目的輸出,而函數(shù)只有單一的返回值
- 只能通過(guò)調(diào)用程序來(lái)執(zhí)行存儲(chǔ)過(guò)程,而函數(shù)可以在SQL語(yǔ)句中使用
修改數(shù)據(jù)
- 修改策略:使用“軟刪除(使用表中特定的列來(lái)標(biāo)記該行數(shù)據(jù)是否有效)”技術(shù)替代真正的刪除;插入新行時(shí)在特定列中標(biāo)記準(zhǔn)確的插入日期和時(shí)間以便出錯(cuò)時(shí)對(duì)其進(jìn)行刪除;使用單獨(dú)的表來(lái)保存事務(wù)所要更新的數(shù)據(jù)通常是明智的選擇。請(qǐng)永遠(yuǎn)記住,SQL中沒(méi)有撤銷(xiāo)命令。
- 插入數(shù)據(jù):使用
INSERT命令來(lái)插入指定數(shù)據(jù),注意不需要為自增型的列指定數(shù)據(jù),數(shù)據(jù)庫(kù)會(huì)自動(dòng)處理它;另外,Oracle不允許一次插入多行數(shù)據(jù),需要分開(kāi)書(shū)寫(xiě)- 插入
INSERT語(yǔ)句中指定的具體數(shù)據(jù)-- 向customer表插入兩條新數(shù)據(jù) INSERT INTO customers (first_name, last_name, state) -- 只要列名是正確的,它們的順序無(wú)所謂 -- 當(dāng)這里的列名順序與數(shù)據(jù)庫(kù)中的物理順序一致時(shí)可省略它們,但強(qiáng)烈不建議這么做 VALUES ('Virginia', 'Jones', 'OH'), -- VALUES關(guān)鍵字后的數(shù)據(jù)列,要與INSERT INTO后的列相對(duì)應(yīng) ('Clark', 'Woodland', 'CA') - 插入用一條
SELECT語(yǔ)句指定的數(shù)據(jù)-- 將customer_transaction中的RI州的用戶(hù)插入到customer表中 INSERT INTO customer (first_name, last_name, state) SELECT fn, ln, state -- 這里選中列的順序需要與INSERT INTO 語(yǔ)句中的順序一致 FROM customer_transactions WHERE state = 'RI'
- 插入
- 刪除數(shù)據(jù):使用
DELETE命令來(lái)刪除一條數(shù)據(jù),通常是一整行(刪除某行中的列沒(méi)有意義,那屬于修改數(shù)據(jù)的范疇)-- 刪除數(shù)據(jù)的一般寫(xiě)法 DELETE FROM table_name WHERE conditions -- 可以使用SELECT語(yǔ)句來(lái)驗(yàn)證刪除結(jié)果 SELECT COUNT (*) -- 使用聚合函數(shù)COUNT來(lái)統(tǒng)計(jì)被刪除數(shù)據(jù)的數(shù)量以確認(rèn)是否全部都被刪除了 FROM table_name WHERE conditions -- 清空一個(gè)表中的所有數(shù)據(jù),可以使用TRUNCATE TABLE語(yǔ)句 TRUNCATE TABLE customers -- 上面的語(yǔ)句與下面的DELETE語(yǔ)句效果基本相同 DELETE FROM customers -- 唯一不同在于,TRUNCATE TABLE語(yǔ)句重置了自增列,而DELETE語(yǔ)句沒(méi)有 - 更新(修改)數(shù)據(jù):刪除數(shù)據(jù)只需要指定刪除的行即可,但更新數(shù)據(jù)是針對(duì)具體行中的具體列,所以需要首先指定更新哪些列,然后指定更新這些列中的哪些行
- 使用指定的具體數(shù)據(jù)更新數(shù)據(jù)
-- 更新數(shù)據(jù)的一般格式 UPDATE table SET column1 = expression1, column2 = expression2 -- repeat any number of time WHERE conditions -- 如果沒(méi)有指定行,該句會(huì)把所有行的指定列都更新一次 - 使用子查詢(xún)中的數(shù)據(jù)修改數(shù)據(jù)(使用一個(gè)表中的數(shù)據(jù)來(lái)更新另一個(gè)表中的數(shù)據(jù))
-- 一般格式 UPDATE table -- 指定要更新的表 SET table.column_1 = -- 指定需要更新的列1 ( SELECT another_table.column_1 -- 子查詢(xún)從另一表中獲取數(shù)據(jù),并通過(guò)主鍵(也可是其它)來(lái)進(jìn)行匹配 FROM another_table WHERE another_table.auto_increment_primary_key = table.auto_increment_primary_key ) SET table.column_2 = -- 指定需要更新的列2 ( SELECT another_table.column_2 FROM another_table WHERE another_table.auto_increment_primary_key = auto_increment_primary_key.column_2 ) WHERE EXISTS -- 指定需要更新的行,使用子查詢(xún)指定只更新table中存在于another_table中的行 ( SELECT * FROM another_table WHERE another_table.auto_increment_primary_key = table.auto_increment_primary_key )
- 使用指定的具體數(shù)據(jù)更新數(shù)據(jù)
維護(hù)表
- 回顧SQL語(yǔ)言的三種組成部分:數(shù)據(jù)操縱語(yǔ)言(Data Manipulation Language,DML,對(duì)數(shù)據(jù)庫(kù)中或者更詳細(xì)地說(shuō)是表中的數(shù)據(jù)進(jìn)行增刪改查操作)、數(shù)據(jù)定義語(yǔ)言(Data Definition Language,DDL,對(duì)數(shù)據(jù)庫(kù)中的表及其索引進(jìn)行增刪改查)、和數(shù)據(jù)控制語(yǔ)言(Data Control Language,DCL,維護(hù)數(shù)據(jù)庫(kù)安全)。本章主要講述DDL,但前文也已經(jīng)用到過(guò)DDL,視圖
VIEW、過(guò)程PROCEDURE需要用到的都是DDL - 添加或修改表和索引的SQL語(yǔ)句很復(fù)雜,但是我們無(wú)需了解細(xì)節(jié),數(shù)據(jù)庫(kù)軟件通常提供了圖形化的工具來(lái)修改表的結(jié)構(gòu),而不一定需要使用SQL語(yǔ)句
- 表屬性:表(Table)是數(shù)據(jù)庫(kù)中最重要的對(duì)象,數(shù)據(jù)庫(kù)中所有數(shù)據(jù)物理地存儲(chǔ)在表中,沒(méi)有了表數(shù)據(jù)庫(kù)中的一切也就沒(méi)有意義了。前文已經(jīng)介紹過(guò)一些表的屬性,主鍵、外鍵、數(shù)據(jù)類(lèi)型、自增型列等等
- 表的列
- 列名:表中的每個(gè)列都必須有唯一的列名
- 數(shù)據(jù)類(lèi)型:決定列可以包含什么樣的數(shù)據(jù)
- 是否自增型:表中每增加一行,該列會(huì)以升序序列自動(dòng)賦值(術(shù)語(yǔ)auto-increment是MySQL中的的特定用法,Oracle沒(méi)有自增型屬性)
- 默認(rèn)值
- 表的列
- 主鍵和索引
- 主鍵:只能指定一個(gè)列作為主鍵,目的是保證這個(gè)列包含唯一值(所以不允許它們包含
NULL值);實(shí)際上主鍵可以跨越多個(gè)列,叫做復(fù)合主鍵(當(dāng)希望使用電影名稱(chēng)列來(lái)作為主鍵時(shí)可能會(huì)存在重復(fù)名稱(chēng), 這時(shí)可以使用電影名稱(chēng)+年份兩個(gè)列作為復(fù)合主鍵來(lái)唯一地定義每部電影) - 索引:索引是一種物理結(jié)構(gòu),目的是當(dāng)SQL語(yǔ)句中包含該列的時(shí)候,可以加速數(shù)據(jù)檢索,缺點(diǎn)是需要更多的磁盤(pán)空間,并且會(huì)減慢更新數(shù)據(jù)時(shí)的速度
- 主鍵:只能指定一個(gè)列作為主鍵,目的是保證這個(gè)列包含唯一值(所以不允許它們包含
- 外鍵:
- 外鍵定義:外鍵是從一個(gè)表中的一個(gè)列到另一個(gè)不同的表中的列的直接引用,含有外鍵的表為“子表”,被外鍵引用的表被稱(chēng)為“父表”
- 外鍵級(jí)聯(lián)(Cascade):當(dāng)父表有更新或刪除時(shí),會(huì)自動(dòng)更新或刪除子表中的關(guān)聯(lián)行
- Set Null:當(dāng)父表有更新或刪除時(shí),如果影響到子表,是否把子表中關(guān)聯(lián)行的外鍵設(shè)置為
NULL
- 創(chuàng)建表:使用
CREATE TABLE語(yǔ)句來(lái)創(chuàng)建表及其屬性(列),不同數(shù)據(jù)庫(kù)之間存在差異:
使用-- Microsoft SQL Server CREATE TABLE my_table ( column_1 INT IDENTITY (1, 1) PRIMARY KEY NOT NULL, -- 列名column_1,INT類(lèi)型,自增型,主鍵,不能為NULL column_2 NOT NULL REFERENCES related_table (first_column), -- 列名column_2,INT類(lèi)型,不能為NULL,外鍵,關(guān)聯(lián)到related_table表的first_column列 column_3 VARCHAR (25) NULL, -- 列名column_3,VARCHART類(lèi)型,可以是NULL column_4 FLOAT NULL DEFAULT (10) -- 列名column_4,F(xiàn)LOAT類(lèi)型,可以是NULL ) -- My SQL CRAET TABLE my_table column_1 INT AUTO_INCREMENT PRIMARY KEY NOT NULL, column_2 INT NOT NULL, column_3 VARCHAR (25) NULL, column_4 FLOAT NULL DEFAULT 10 NULL, CONSTRAINT FOREIGN KEY (column_2) REFERENCE 'related_table' (first_column) -- 指定外鍵 -- Oracle CREATE TABLE my_table ( column_1 INT PRIMARY KEY NOT NULL, -- Oracle不允許有自增型的列 column_2 INT NOT NULL, column_3 VARCHAR2 (25) null, column_4 FLOAT DEFAULT 10 NULL CONSTRAINT "foreign_key" FOREIGN KEY (column_2) REFERENCES related_table (first_column) )ALTER TABLE語(yǔ)句修改表的具體屬性,該語(yǔ)句的復(fù)雜性及數(shù)據(jù)庫(kù)差異巨大,這里不再展開(kāi);使用DROP TABLE table_name語(yǔ)句來(lái)刪除一個(gè)表-- 修改表 ALTER TABLE my_table DROP COLUMN column_3 -- 刪除表 DROP TABLE my_table - 創(chuàng)建索引:使用
CREATE INDEX語(yǔ)句,用來(lái)在創(chuàng)建表之后創(chuàng)建索引,使用ALTER INDEX語(yǔ)句來(lái)添加和修改索引-- 創(chuàng)建索引 CREATE INDEX index_2 ON my_table (column_4) -- 刪除索引 DROP INDEX index_2 ON my_table
數(shù)據(jù)庫(kù)設(shè)計(jì)原理與顯示數(shù)據(jù)的策略(略)
- 關(guān)系型數(shù)據(jù)庫(kù)是一個(gè)數(shù)據(jù)集合,數(shù)據(jù)庫(kù)中的表以某些方式相互關(guān)聯(lián)。
- SQL語(yǔ)句僅僅是使用數(shù)據(jù)庫(kù)的工具,數(shù)據(jù)庫(kù)設(shè)計(jì)則是另外一個(gè)更為重要的話(huà)題?!禨QL初學(xué)者指南》中對(duì)這個(gè)話(huà)題進(jìn)行了簡(jiǎn)單的概括:規(guī)范化及其替代方法,這里將不再展開(kāi)。
- 關(guān)于這個(gè)話(huà)題建議閱讀另外的一些書(shū)籍:《SQL必知必會(huì)》、《高性能MySQL》
