SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师
目錄
第一部分:基礎——增刪查改
【第一章】做好準備 Getting Started (時長25分鐘)
【第二章】在單一表格中檢索數據 Retrieving Data From a Single Table (時長53分鐘)
【第三章】在多張表格中檢索數據 Retrieving Data From Multiple Tables (時長1小時2分)
【第四章】插入、更新和刪除數據 Inserting, Updating, and Deleting Data (時長42分鐘)
第二部分:基礎進階——匯總、復雜查詢、內置函數
【第五章】匯總數據 Summarizing Data (時長33分鐘)
【第六章】編寫復雜查詢 Writing Complex Query (時長45分鐘)
【第七章】MySQL的基本函數 Essential MySQL Functions (時長33分鐘)
第三部分:提高效率——視圖、存儲過程、函數
【第八章】視圖 Views (時長18分鐘)
【第九章】存儲過程 Stored Procedures (時長48分鐘)
第四部分:高階主題——觸發器、事件、事務、并發
【第十章】觸發器和事件 Triggers and Events (時長22分鐘)
【十一章】事務和并發 Transactions and Concurrency (時長49分鐘)
第五部分:脫穎而出——數據類型、設計數據庫、索引、保護
【十二章】數據類型 Data Types (時長35分鐘)
【十三章】設計數據庫 Designing Databases (時長1時30分)
【十四章】高效的索引 Indexing for High Performance (時長58分鐘)
【十五章】保護數據庫 Securing Databases (時長20分鐘)
【第一章】做好準備
什么是SQL
- 有關系型和非關系型兩類數據庫,在更流行的關系型數據庫中,我們把數據存儲在通過某些關系相互關聯的數據表中,每張表儲存特定的一類數據,這正是關系型數據庫名稱的由來。(如:顧客表通過顧客id與訂單表相聯系,訂單表又通過商品id與商品表相聯系)
- SQL(Structured Query Language,結構化查詢語言)是專門用來處理(包括查詢和修改)關系型數據庫的標準語言
- 不同關系型數據庫管理系統語法(MySQL、SQL Server、Oracle)略有不同,但都是基于標準SQL,本課使用最流行的開源關系型數據庫管理系統,MySQL
【第二章】在單一表格中檢索數據
選擇子句
-
SELECT 是列/字段選擇語句,可選擇列,列間數學表達式,特定值或文本,可用AS關鍵字設置列別名(AS可省略),注意 DISTINCT 關鍵字的使用。
-
SQL會完全無視大小寫(絕大數情況下的大小寫)、多余的空格(超過一個的空格)、縮進和換行,SQL語句間完全由分號 ; 分割
-
單價漲價10%作為新單價 :
SELECT
name,
unit_price,
unit_price * 1.1 ‘new price’
FROM products
如上面這個例子所示,取別名時,AS 可省,空格后跟別名就行,可看作是SQL會將將列變量及其數學運算之后的第一個空格識別為AS
WHERE子句
- WHERE 是行篩選條件,實際是一行一行/一條條記錄依次驗證是否符合條件,進行篩選
- 實例
USE sql_store;
SELECT *
FROM customers
WHERE points > 3000
/WHERE state != ‘va’ – ‘VA’/'va’一樣
- 比較運算符中注意等于是一個等號而不是兩個等號
- 也可對日期或文本進行比較運算,注意SQL里日期的標準寫法及其需要用引號包裹這一點
WHERE birth_date > ‘1990-01-01’
AND, OR, NOT運算符
USE sql_store;
SELECT *
FROM customers
WHERE birth_date > ‘1990-01-01’ AND points > 1000
/WHERE birth_date > ‘1990-01-01’ OR
points > 1000 AND state = ‘VA’
- AND優先級高于OR,但最好加括號,更清晰
- NOT的用法 :
WHERE NOT (birth_date > ‘1990-01-01’ OR points > 1000)
IN運算符
用IN運算符將某一屬性與多個值(一系列值)進行比較
實質是多重相等比較運算條件的簡化
案例
選出’va’、‘fl’、'ga’三個州的顧客
USE sql_store;
SELECT * FROM customers
WHERE state = ‘va’ OR state = ‘fl’ OR state = ‘ga’
- 用 IN 操作符簡化該條件
WHERE state IN (‘va’, ‘fl’, ‘ga’) - 可加NOT
WHERE state NOT IN (‘va’, ‘fl’, ‘ga’) - 庫存量剛好為49、38或72的產品 :
USE sql_store;
select * from products
where quantity_in_stock in (49, 38, 72)
BETWEEN運算符
用于表達范圍型條件
用AND而非括號
閉區間,包含兩端點
也可用于日期,畢竟日期本質也是數值,日期也有大小(早晚),可比較運算
- 選出積分在1k到3k的顧客 :
USE sql_store;
select * from customers
where points >= 1000 and points <= 3000
等效簡化為:
WHERE points BETWEEN 1000 AND 3000
注意兩端都是包含的 不能寫作BETWEEN (1000, 3000)!別和IN的寫法搞混
- 選出90后的顧客 :
SELECT * FROM customers
WHERE birth_date BETWEEN ‘1990-01-01’ AND ‘2000-01-01’
LIKE運算符
模糊查找,查找具有某種模式的字符串的記錄/行
過時用法(但有時還是比較好用,之后發現好像用的還是比較多的),下節課的正則表達式更靈活更強大
注意和正則表達式一樣都是用引號包裹表示字符串
USE sql_store;
SELECT * FROM customers
WHERE last_name like ‘brush%’ / ‘b____y’
引號內描述想要的字符串模式,注意SQL(幾乎)任何情況都是不區分大小寫的
兩種通配符:
% 任何個數(包括0個)的字符(用的更多)
_ 單個字符
- 分別選擇滿足如下條件的顧客:
地址包含 ‘TRAIL’ 或 ‘AVENUE’
電話號碼以 9 結束
USE sql_store;
select *
from customers
where address like ‘%Trail%’ or
address like ‘%avenue%’
LIKE 執行優先級在邏輯運算符之后,畢竟 IN BETWEEN LIKE 本質可看作是比較運算符的簡化,應該和比較運算同級,數學→比較→邏輯,始終記住這個順序,上面這個如果用正則表達式會簡單得多
where phone like ‘%9’
/where phone not like ‘%9’
LIKE的判斷結果也是個TRUE/FASLE的問題,任何邏輯值/布林值都可前置NOT來取反
REGEXP運算符
正則表達式,在搜索字符串方面更為強大,可搜索更復雜的模板
實例
USE sql_store;
select * from customers
where last_name like ‘%field%’
等效于:
where last_name regexp ‘field’
regexp 是 regular expression(正則表達式) 的縮寫
正則表達式可以組合來表達更復雜的字符串模式
where last_name regexp ‘^mac|field$|rose’
where last_name regexp ‘[gi]e|e[fmq]’ – 查找含ge/ie或ef/em/eq的
where last_name regexp ‘[a-h]e|e[c-j]’
正則表達式總結:
符號 意義
^ 開頭
$ 結尾
[abc] 含abc
[a-c] 含a到c
| logical or
(正則表達式用法還有更多,自己去查)
練習
分別選擇滿足如下條件的顧客:
first names 是 ELKA 或 AMBUR
last names 以 EY 或 ON 結束
last names 以 MY 開頭 或包含 SE
last names 包含 BR 或 BU
select *
from customers
where first_name regexp ‘elka|ambur’
/where last_name regexp ‘ey∣on|on∣on’
/where last_name regexp ‘^my|se’
/where last_name regexp ‘b[ru]’/‘br|bu’
IS NULL運算符
找出空值,找出有某些屬性缺失的記錄
- 找出電話號碼缺失的顧客,也許發個郵件提醒他們之類
USE sql_store;
select * from customers
where phone is null/is not null
注意是 IS NULL 和 IS NOT NULL 這里 NOT 不是前置于布林值,而是更符合英語語法地放在了be動詞后
- 找出還沒發貨的訂單(在線商城管理員的常見查詢需求)
USE sql_store;
select * from orders
where shipper_id is null
- 回顧 :
3~9 節全在講WHERE子句中條件的具體寫法 :
第3節:比較運算 > < = >= <= !=
第4節:邏輯運算 AND、OR、NOT
5~9節:特殊的比較運算(是否符合某種條件):IN 和 BETWEEN、LIKE 和 REGEXP、IS NULL
所以總的來說WHERE條件就是
數學運算 → 比較運算(包括特殊的比較運算)→ 邏輯運算
邏輯層次和執行優先級也是按照這三個的順序來的。
ORDER BY子句
排序語句,和 SELECT …… 很像:
可多列
可以是列間的數學表達式
可包括任何列,包括沒選擇的列(MySQL特性,其它DBMS可能報錯),
可以是之前定義好的別名列(MySQL特性,甚至可以是用一個常數設置的列別名)
任何一個排序依據列后面都可選加 DESC
注意
最好別用 ORDER BY 1, 2(表示以 SELECT …… 選中列中的第1、2列為排序依據) 這種隱性依據,因為SELECT選擇的列一變就容易出錯,還是顯性地寫出列名作為排序依據比較好
注:workbench 中扳手圖標可打開表格的設計模式,查看或修改表中各列(屬性),可以看到誰是主鍵。省略排序語句的話會默認按主鍵排序
- 實例 :
USE sql_store;
select name, unit_price * 1.1 + 10 as new_price
from products
order by new_price desc, product_id
– 這兩個分別是 別名列 和 未選擇列,都用到了 MySQL 特性
- 訂單2的商品按總價降序排列 :
法1. 可以以總價的數學表達式為排序依據
select * from order_items
where order_id = 2
order by quantity * unit_price desc
– 列間數學表達式
法2. 或先定義總價別名,在以別名為排序依據
select *, quantity * unit_price as total_price
from order_items
where order_id = 2
order by total_price desc
– 列別名
LIMIT子句
限制返回結果的記錄數量,“前N個” 或 “跳過M個后的前N個”
- 實例
USE sql_store;
select * from customers
limit 3 / 300 / 6, 3
6, 3 表示跳過前6個,取第7~9個,6是偏移量,
如:網頁分頁 每3條記錄顯示一頁 第3頁應該顯示的記錄就是 limit 6, 3
- 找出積分排名前三的死忠粉
USE sql_store;
select *
from customers
order by points desc
limit 3
- 回顧
SELECT 語句完結了,里面的子句順序固定要記牢,順序亂會報錯
select from where + order by limit
縱選列,確定表,橫選行(各種條件寫法和組合要清楚熟悉),最后再進行排序和限制
【第三章】在多張表格中檢索數據
內連接
- 各表分開存放是為了減少重復信息和方便修改,需要時可以根據相互之間的關系連接成相應的合并詳情表以滿足相應的查詢。FROM JOIN ON 語句就是告訴sql: 將哪幾張表以什么基礎連接/合并起來。
- 這種有多表合并的查詢語句可分兩部分從后往前看:
- 關于表別名 :之前在SELECT中給選定的列加別名主要是為了得到更有意義的列名,這里在 FROM JOIN 中給表加別名主要是為了簡化
- 因為別名需要在 WHERE JOIN 語句中確定等原因,最好先SELECT * FROM 選擇全部,等寫好了 FROM JOIN ON 等后面的語句,即確定了選哪些表以及怎么鏈接它們并取好了表別名后,再回頭去 SELECT 里細化明確需要的列。
跨數據庫連接(合并)
- 有時需要選取不同庫的表的列,其他都一樣,就只是WHERE JOIN里對于非現在正在用的庫的表要加上庫名前綴而已。依然可用別名來簡化
- 可見只有非當前使用的庫才要加庫前綴
自連接
- 一個表和它自己合并。如下面的例子,員工的上級也是員工,所以也在員工表里,所以想得到的有員工和他的上級信息的合并表,就要員工表自己和自己合并,用兩個不同的表別名即可實現。這個例子中只有兩級,但也可用類似的方法構建多層級的組織結構。
- 自合并必然每列都要加表前綴,因為每列都同時在兩張表中出現。另外,兩個 first_name 列有歧義,注意將最后一列改名為 manager 使得結果表更易于理解
多表連接
- FROM 一個核心表A,用多個 JOIN …… ON …… 分別通過不同的鏈接關系鏈接不同的表B、C、D……,通常是讓表B、C、D……為表A提供更詳細的信息從而合并為一張詳情合并版A表。將得到一個合并了BCD……等表詳細信息的詳情合并版A表。真實工作場景中有時甚至要合并十多張表
- 訂單表同時鏈接顧客表和訂單狀態表,合并為有顧客和狀態信息的詳細訂單表
- 同理,支付記錄表鏈接顧客表和支付方式表形成支付記錄詳情表
復合連接條件
- 像訂單項目(order_items)這種表,訂單id和產品id合在一起才能唯一表示一條記錄,這叫復合主鍵,設計模式下也可以看到兩個字段都有PK標識,訂單項目備注表(order_item_notes)也是這兩個復合主鍵,因此他們兩合并時要用復合條件:FROM 表1 JOIN 表2 ON 條件1 【AND】 條件2
- 將訂單項目表和訂單項目備注表合并
隱式連接語法
- 就是用FROM WHERE取代FROM JOIN ON
- 盡量別用,因為若忘記WHERE條件篩選語句,不會報錯但會得到交叉合并(cross join)結果:即10條order會分別與10個customer結合,得到100條記錄。最好使用顯性合并語法,因為會強制要求你寫合并條件ON語句,不至于漏掉。
- 合并顧客表和訂單表,顯性合并:
- 隱式合并語法:
- 注意 FROM 子句里的逗號,就像 SELECT 多條列用逗號隔開一樣,FROM 多個表也用逗號隔開,此時若忘記WHERE條件篩選語句則得到這幾張表的交叉合并結果
- 這里也可以看得出來,ON/USING 和 WHERE 以及后面會學的 HAVING 的作用是類似的,本質上都是對行進行篩選的條件語句,只不過使用的位置不一樣而已
外連接
- (INNER) JOIN 結果只包含兩表的交集,另外注意“廣播(broadcast)”效應
- LEFT/RIGHT (OUTER) JOIN 結果里除了交集,還包含只出現在左/右表中的記錄
- 合并顧客表和訂單表,用 INNER JOIN:
- 這樣是INNER JOIN,只展示有訂單的顧客(及其訂單),也就是兩張表的交集,但注意這里因為一個顧客可能有多個訂單,所以INNER JOIN以后顧客信息其實是是廣播了的,即一條顧客信息被多條訂單記錄共用,當然 這叫廣播(broadcast)效應,是另一個問題,這里關注的重點是 INNER JOIN 的結果確實是兩表的交集,是那些同時有顧客信息和訂單信息的記錄。
- 若要展示全部顧客(及其訂單,如果有的話),要改用LEFT (OUTER) JOIN,結果相較于 INNER JOIN 多了沒有訂單的那些顧客,即只有顧客信息沒有訂單信息的記錄
- 當然,也可以調換左右表的順序(即調換FROM和JOIN的對象)再 RIGHT JOIN,即:
- 若要展示全部訂單(及其顧客),就應該是 orders RIGHT JOIN customers,結果相較于 INNER JOIN 多了沒有顧客的那些訂單,即只有訂單信息沒有顧客信息的記錄。(注:因為這里所有訂單都有顧客,所以這里 RIGHT JOIN 結果和 INNER JOIN 一樣)
- 展示各產品在訂單項目中出現的記錄和銷量,也要包括沒有訂單的產品
多表外連接
- 與內連接類似,我們可以對多個表(3個及以上)進行外連接,最好只用 JOIN 和 LEFT JOIN
- 查詢顧客、訂單和發貨商記錄,要包括所有顧客(包括無訂單的顧客),也要包括所有訂單(包括未發出的)
- 最佳實踐 :雖然可以調換順序并用 RIGHT JOIN,但作為最佳實踐,最好調整順序并統一只用 [INNER] JOIN 和 LEFT [OUTER] JOIN(總是左表全包含),這樣,當要合并的表比較多時才方便書寫和理解而不易混亂
- 查詢 訂單 + 顧客 + 發貨商 + 訂單狀態,包括所有的訂單(包括未發貨的),其實就只是前兩個優先級變了一下,是要看全部訂單而非全部顧客了
總結
以上是生活随笔為你收集整理的SQL进阶教程 | 史上最易懂SQL教程 5小时零基础成长SQL大师的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 尚硅谷最新版JavaWeb全套教程,ja
- 下一篇: Redis实现发布与订阅(转)