大家不要只收藏不點贊啊!支持一下吧
目錄
- 必須要看的前言
- 1 什么是資料庫、SQL和MySQL?
- 1.1 資料庫基礎
- 1.1.1 什么是資料庫
- 1.1.2 表
- 1.1.3 列和資料型別
- 1.1.4 行
- 1.1.5 主鍵
- 1.2 什么是SQL
- 1.3 MySQL簡介
- 2 排序
- 3 過濾
- 3.1 基礎操作
- 3.2 LIKE 運算子
- 3.2.1 百分號通配符(%)
- 3.2.2 下劃線通配符(_)
- 3.3 正則運算式搜索
- 3.3.1 空白的元字符
- 3.3.2 匹配字符類
- 3.3.3 重復元字符
- 3.3.4 定位元字符
- 4 資料處理函式
- 4.1 字串函式
- 4.2 日期和時間處理函式
- 4.3 數值處理函式
- 5 匯總資料
- 5.1 聚合函式
- 5.2 聚集不同值
- 6 分組資料
- 6.1 創建分組
- 6.2 過濾分組
- 6.3 分組和排序
- 6.4 SELECT子句順序
- 7 聯結表
- 7.1 內部鏈接
- 7.2 聯結多個表
- 7.3 創建高級聯結
- 7.4 外部聯結 OUTER JOIN
- 7.5 組合查詢 UNION
- 7.5.1 UNION和UNION ALL的區別
- 8 插入資料
- 9 修改資料
- 10 洗掉資料
- 11 MySQL引擎型別
- 12 MySQL特性
- 13 視圖
- 13.1 什么是視圖?
- 13.2 為什么使用視圖?
- 13.3 使用視圖
- 14 匯出資料
- 15 視窗函式
- 15.1 rank()、dense_rank()和row_number()
- 15.2 CUME_DIST()和PERCENT_RANK()
- 15.3 FIRST_VALUE()和LAST_VALUE()
- 15.4 LAG()和LEAD()
- 15.5 NTH_VALUE()
- 15.6 NTILE()
必須要看的前言
收藏本篇文章,意味著你擁有了一份超級完善的MySQL“語言書籍”,本篇博客幾乎涵蓋了所有MySQL知識點,文中也有特別標注了哪些是面試提問熱點或者是應該著重掌握的知識點,你也可以把這篇博客當作一本小“詞典”,遇到遺忘了的知識點也隨時可以查閱,總而言之,希望大家喜歡這篇博客,也更希望這篇博客能給大家帶來幫助,
1 什么是資料庫、SQL和MySQL?
那在了解MySQL之前,我們需要先了解一下什么是SQL,了解SQL之前,先了解資料庫有哪些基礎知識點?
1.1 資料庫基礎
1.1.1 什么是資料庫
🔴 資料庫是一個以某種有組織的方式存盤的資料集合,即保存有組織的資料的容器(通常是一個檔案或一組檔案),
1.1.2 表
🔴 表是一種結構化的檔案,可用來存盤某種特定型別的資料,即某種特定型別資料的結構化清單,
1.1.3 列和資料型別
🔴 列:表中的一個欄位,所有表都是由一個或多個列組成的,
🔴 資料型別:所容許的資料的型別,每個表列都有相應的資料型別,它限制(或容許)該列中存盤的資料,
1.1.4 行
🔴 表中的資料是按行存盤的,所保存的每個記錄存盤在自己的行內,如果將表想象為網格,網格中垂直的列為表列,水平行為表行,
1.1.5 主鍵
🔴 列(或一組列),其值能夠唯一區分表中每個行,
表中每一行都應該有可以唯一標識自己的一列(或一組列),一個顧客表可以使用顧客編號列,而訂單表可以使用訂單ID,雇員表可以使用雇員ID或雇員社會保險號,
主鍵通常定義在表的一列上,但這并不是必需的,也可以一起使用多個列作為主鍵,在使用多列作為主鍵時,上述條件必須應用到構成主鍵的所有列,所有列值的組合必須是唯一的(但單個列的值可以不唯一),
1.2 什么是SQL
🔴 SQL是結構化查詢語言(Structured Query Language)的縮寫,是一種專門用來與資料庫通信的語言,
簡單來講,SQL就是程式員與資料庫聯系的工具,幾乎所有重要的DBMS(資料庫管理系統)都支持SQL,
1.3 MySQL簡介
🔴 MySQL是一種DBMS,也就是一種資料庫軟體,
而且很多的公司和開發人員都喜歡用MySQL,為啥?因為人家是開放源代碼的,免費使用,而且MySQL執行速度很快,且容易安裝和使用,
簡單介紹完這些背景知識后,后面有關如何連接資料庫以及如何用SELECT陳述句進行簡單的檢索操作我就不講了,直接上正菜,
2 排序
🔴 ORDER BY默認使用升序排列(同末尾加ASC),DESC關鍵字只應用到直接位于前面的列名
- 使用多個列排序,不同的列使用的順序不同
SELECT prod_id, prod_price, prod_name
FROM product
ORDER BY prod_price DESC, prod_name;
- 使用ORDER BY 和 LIMIT組合獲取最N值
SELECT prod_price
FROM products
ORDER BY prod_price DESC
LIMIT 1;
🔴 LIMIT用法講解:
LIMIT 5 等價于 LIMIT 0, 5, 即查詢(0+1)到(0+5)的資料,也就是1-5的資料,也就是說這里的0是查詢的資料起點的前一位,5是查詢的數量,
LIMIT 2 OFFSET 3 等價于 LIMIT 3 2,即查詢(3+1)到(3+2)的資料,也就是4-5的資料,也就是說這里的3是查詢的資料起點的前一位,2是查詢的數量,
3 過濾
🔴 WHERE 子句可操作內容
| 運算子 | 說明 |
|---|---|
| = | 等于 |
| <> | 不等于 |
| != | 不等于 |
| < | 小于 |
| <= | 小于等于 |
| > | 大于 |
| >= | 大于等于 |
| BETWEEN … AND … | 指定兩個值之間 |
3.1 基礎操作
- 獲取范圍值
SELECT prod_name, prod_price
FROM products
WHERE prod_price BETWEEN 5 AND 10;
- 空值檢查
SELECT prod_name
FROM products
WHERE prod_price IS NULL
# WHERE IFNULL(prod_price)
- IN取的合法值由逗號分隔的清單
SELECT prod_name, prod_price
FROM products
WHERE vend_id IN (1002,1003)
ORDER BY prod_name
IN運算子一般比OR運算子速度更快,此外,IN可以包含其他SELECT陳述句,能夠動態簡歷WHERE子句,
AND、OR、NOT這些運算子沒啥好說的,但是要注意,任何時候使用具有AND和OR運算子的WHERE子句,都應該使用圓括號明確地分組運算子,不要過分依賴默認計算次序,即使它確實是你想要的東西也是如此,使用圓括號沒有什么壞處,它能消除歧義,
另外,應盡量避免在 WHERE子句中使用上述運算子合like運算子,否則將引擎放棄使用索引而進行全表掃描,
3.2 LIKE 運算子
🔴 LIKE運算子可以用于模糊搜索時使用,即你不知道完整的資料如何,但你知道部分資訊,就可以用到LIKE,例如,怎樣搜索產品名中包含文本anvil的所有產品?用簡單的比較運算子肯定不行,必須使用通配符,
注意:通配符搜索花費的時間更多;在確定是要通配符時,除非絕對有必要,不要把他們放在搜索模式的開始處,否則搜索起來是最慢的,
3.2.1 百分號通配符(%)
🔴 %表示任何字符出現的任意次數,
- 以下代碼找出所有以詞per開頭的產品
SELECT prod_id, prod_name
FROM products
WHERE prod_name LIKE 'per%'
- 同樣,也可以是
WHERE prod_name LIKE '%anvil%'
3.2.2 下劃線通配符(_)
🔴 用處與%一樣,但是只能匹配單個字符,
也就是說%可以匹配0-無窮的字符,但_只能匹配單個字符,
3.3 正則運算式搜索
隨著過濾條件的復雜性的增加,WHERE子句本身的復雜性也有必要增加,這個時候,就需要用到正則運算式了,
正則運算式的作用是匹配文本,將一個模式(正則運算式)與一個文本串進行比較,MySQL用WHERE子句對正則運算式提供了初步的支持,允許你指定正則運算式,過濾SELECT檢索出的資料,
- 如下代碼所示,如果對應的列中出現了REGEXP后面的字串,則回傳它,
WHERE prod_name REGEXP '1000'
正則字串匹配不區分大小寫,如果需要區分可以使用REGEXP BINARY 'JetPack'
正則運算式中要匹配. -等特殊字符需要加反義字符\\,
3.3.1 空白的元字符
| 元字符 | 含義 |
|---|---|
| \\f | 換頁 |
| \\n | 換行 |
| \\r | 回車 |
| \\t | 制表 |
| \\v | 縱向制表 |
3.3.2 匹配字符類
| 元字符 | 含義 |
|---|---|
| [:alnum:] | 任意字母和數字(同[a-zA-Z0-9]) |
| [:alpha:] | 任意字符(同[a-zA-Z]) |
| [:blank:] | 空格和制表(同[\\t]) |
| [:cntrl:] | ASCII控制字符(ASCII 0到31和127) |
| [:digit:] | 任意數字(同[0-9]) |
| [:graph:] | 與[:print:]相同,但不包括空格 |
| [:lower:] | 任意小寫字母(同[a-z]) |
| [:print:] | 任意可列印字符 |
| [:punct:] | 既不在[:alnum:]又不在[:cntrl:]中的任意字符 |
| [:space:] | 包括空格在內的任意空白字符(同[\\f \\n \\r \\t \\v]) |
| [:upper:] | 任意大寫字母(同[A-Z]) |
| [:xdigit:] | 任意十六進制數字(同[a-fA-F0-9]) |
3.3.3 重復元字符
| 元字符 | 含義 |
|---|---|
| * | 0個或多個匹配 |
| + | 1個或多個匹配(等于{1,}) |
| ? | 0個或1個匹配(等于{0,1}) |
| {n} | 指定數目的匹配 |
| {n,} | 不少于指定數目的匹配 |
| {n,m} | 匹配數目的范圍(m不超過255) |
- 匹配連在一起的四位數字:
WHERE prod_name REGEXP '[[:digit:]]{4}'
- 簡單的正則運算式測驗
SELECT 'hello' REGEXP '[0-9]'
正確會回傳1,否則0,
3.3.4 定位元字符
| 元字符 | 含義 |
|---|---|
| ^ | 文本的開始 |
| $ | 文本的結尾 |
| [[:<:]] | 詞的開始 |
| [[:>:]] | 詞的結尾 |
LIKE和REGEXP的不同在于,LIKE匹配整個串而REGEXP匹配子串,利用定位符,通過用^開始每個運算式,用$結束每個運算式,可以使REGEXP的作用與LIKE一樣,
4 資料處理函式
與其他大多數計算機語言一樣,SQL支持利用函式來處理資料,函式一般是在資料上執行的,它給資料的轉換和處理提供了方便,
4.1 字串函式
| 函式 | 含義 |
|---|---|
| Left() | 回傳串左邊的字符 |
| Length() | 回傳串的長度 |
| Locate() | 找出串的一個子串 |
| Lower() | 將串轉換為小寫 |
| LTrim() | 去掉串左邊的空格 |
| Right() | 回傳串右邊的字符 |
| RTrim() | 去掉串右邊的空格 |
| SubString() | 回傳子串的字符 |
| Upper() | 將串轉換為大寫 |
4.2 日期和時間處理函式
| 函式 | 含義 |
|---|---|
| AddDate() | 增加一個日期(天、周等) |
| AddTime() | 增加一個時間(時、分等) |
| CurDate() | 回傳當前日期 |
| CurTime() | 回傳當前時間 |
| Date() | 回傳日期時間的日期部分 |
| DateDiff() | 計算兩個日期之差 |
| Date_Add() | 高度靈活的日期運算函式 |
| Date_Format() | 回傳一個格式化的日期或時間串 |
| Day() | 回傳一個日期的天數部分 |
| DayOfWeek() | 對于一個日期,回傳對應的星期幾 |
| Hour() | 回傳一個時間的小時部分 |
| Minute() | 回傳一個時間的分鐘部分 |
| Month() | 回傳一個日期的月份部分 |
| Now() | 回傳當前日期和時間 |
| Second() | 回傳一個時間的秒部分 |
| Time() | 回傳一個日期時間的時間部分 |
| Year() | 回傳一個日期的年份部分 |
- 如果要的是日期,一定要使用Date()
SELECT cust_id, order_num
FORM orders
WHERE Date(order_date) = '2005-09-01';
- 檢索一段時間
WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
# WHERE Year(order_date) = 2005 AND Month(order_date) = 9;
4.3 數值處理函式
| 函式 | 含義 |
|---|---|
| Abs() | 回傳一個數的絕對值 |
| Cos() | 回傳一個角度的余弦 |
| Exp() | 回傳一個數的指數值 |
| Mod() | 回傳除操作的余數 |
| Pi() | 回傳圓周率 |
| Rand() | 回傳一個亂數 |
| Sin() | 回傳一個角度的正弦 |
| Sqrt() | 回傳一個數的平方根 |
| Tan() | 回傳一個角度的正切 |
5 匯總資料
5.1 聚合函式
| 函式 | 含義 |
|---|---|
| AVG() | 回傳某列的平均值 |
| COUNT() | 回傳某列的行數 |
| MAX() | 回傳某列的最大值 |
| MIN() | 回傳某列的最小值 |
| SUM() | 回傳某列值之和 |
這里詳細介紹一下COUNT函式,考點來著,
- 使用COUNT(*)對表中行的數目進行計數,不管包含的是空值還是非空值,如果是統計行數的話建議就用COUNT(*),
- 使用COUNT(column)對特定列中具有值得行進行計數,忽略NULL,
- COUNT(1)與COUNT(*)執行結果和效率基本沒差,
5.2 聚集不同值
- 如果只需要包含不同的值,指定DISTINCT引數,否則ALL會被作為默認,這里看做是去重操作,
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM products
WHERE vend_id = 1003;
6 分組資料
6.1 創建分組
SELECT vend_id, COUNT(*) AS num_prods
FROM products
GROUP BY vend_id
如上代碼中,groupby將會對vend_id進行排序并分組資料,
如果分組列中有NULL值,則NULL會被作為一個分組回傳,如果列中有多行NULl值,他們會被分成一組,
GROUP BY子句必須出現在WHERE之后,ORDER BY之前,
6.2 過濾分組
🔴 HAVING 子句:WHERE過濾行,HAVING過濾分組,同樣可以理解為,WHERE在資料分組前進行過濾,HAVING在資料分組后進行過濾,
SELECT cust_id, COUNT(*) AS orders
FROM orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
- 同時進行WHERE和HAVING
SELECT vend_id, COUNT(*) AS num_prods
FROM products
WHERE prod_price >= 10 --首先限制需要的產品價格是10以上的
GROUP BY vend_id
HAVING COUNT(*) >= 2; --然后限制分組后數量需要大于等于2
6.3 分組和排序
🔴 在使用GROUP BY子句的同時,也應該給出ORDER BY子句,這是保證資料正確排序的唯一方法,
SELECT order_num, SUM(quantity*item_price) AS ordertotal
FROM orderitems
GROUP BY order_num
HAVING SUM(quantity*item_price) >= 50
ORDER BY ordertotal;
6.4 SELECT子句順序
- SELECT
- FROM
- WHERE
- GROUP BY
- HAVING
- ORDER BY
- LIMIT
7 聯結表
如果資料存盤在多個表中,怎樣用單條SELECT陳述句檢索出資料?
答案是使用聯結,簡單地說,聯結是一種機制,用來在一條SELECT陳述句中關聯表,因此稱之為聯結,使用特殊的語法,可以聯結多個表回傳一組輸出,聯結在運行時關聯表中正確的行,
7.1 內部鏈接
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
7.2 聯結多個表
SELECT prod_name, vend_name, prod_price, quantity
FROM orderitems, products, vendors
WHERE products.vend_id = vendors.vend_id
AND orderitems.prod_id = products.prod_id
AND order_num = 123;
此種關聯處理是相當耗費資源的,
7.3 創建高級聯結
通過AS關鍵字使用別名,兩點好處:縮短SQL陳述句;允許在單挑SELECT陳述句中多次使用相同的表,
SELECT p1.prod_id, p1.prod_name
FROM products AS p1, products AS p2
WHERE p1.vend_id = p2.vend_id
AND p2.prod_id = 'DTNTR'
如上代碼中使用兩個相同的表分別作為p1, p2,WHERE中選取p2中產品ID為DTNTR的列,此時p2.vend_id就是DTNTR的生產商;p1.vend_id = p2.vend_id 此時意味在p1選取DTNTR的生產商,
7.4 外部聯結 OUTER JOIN
這個其實也是考點,
SQL中的關聯/查詢的方式一共有4種,分別是INNER JOIN(內連接,INNER可以省略)、LEFT OUTER JOIN(左連接,OUTER可以省略)RIGHT OUTER JOIN(右連接,OUTER可以省略)以及FULL JOIN(全連接),
| 連接方式 | 含義 |
|---|---|
| INNER JOIN | 只保留兩張表中完全匹配的結果集, |
| LEFT JOIN | 回傳左表所有的行,而右表中沒有匹配的記錄則會表示為null, |
| RIGHT JOIN | 回傳右表所有的行,而左表中沒有匹配的記錄則會表示為null, |
| FULL JOIN | 在兩張表進行連接查詢時,回傳左表和右表中所有沒有匹配的行, |
值得注意的是,MySQL中是不支持全連接的,但我們可以利用左連接和右連接實作全連接,
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
7.5 組合查詢 UNION
緊跟上文,UNION是啥嘞?
如果說上述提到的各種連接方式概括為一種形式的話,那就是表與表之間左右連接,而UNION則是上下連接,
UNION的使用很簡單,所需做的只是給出每條SELECT陳述句,在各條陳述句之間放上關鍵字UNION,
在進行并時有幾條規則需要注意,
- UNION必須由兩潭訓兩條以上的SELECT陳述句組成,陳述句之間用關鍵字UNION分隔(因此,如果組合4條SELECT陳述句,將要使用3個UNION關鍵字),
- UNION中的每個查詢必須包含相同的列、運算式或聚集函式(不過各個列不需要以相同的次序列出),
- 列資料型別必須兼容:型別不必完全相同,但必須是DBMS可以隱含地轉換的型別(例如,不同的數值型別或不同的日期型別),
最終生成的表的欄位名會以第一個表的欄位名為準,
7.5.1 UNION和UNION ALL的區別
簡單來講,就是使用UNION會洗掉重復的記錄,而UNION ALL則不會,從效率上看,UNION ALL執行效率高于UNION,如果沒有去重的需求,就選用UNION ALL,
8 插入資料
INSERT INTO Customers
VALUES(1,
'Paul',
'USA',
NULL
);
雖然這種語法很簡單,但并不安全,應該盡量避免使用,上面的SQL陳述句高度依賴于表中列的定義次序,并且還依賴于其次序容易獲得的資訊,即使可得到這種次序資訊,也不能保證下一次表結構變動后各個列保持完全相同的次序,因此,撰寫依賴于特定列次序的SQL陳述句是很不安全的,如果這樣做,有時難免會出問題,
撰寫INSERT陳述句的更安全(不過更煩瑣)的方法如下:
INSERT INTO Customers(customer_id,
customer_name,
country,
email)
VALUES(1,
'Paul',
'USA',
NULL
),
(2,
'Wu',
'CHINA',
NULL
);
其優點是,即使表的結構改變,此INSERT陳述句仍然能正確作業,
如何提高整體性能?
資料庫經常被多個客戶訪問,對處理什么請求以及用什么次序處理進行管理是MySQL的任務,INSERT操作可能很耗時(特別是有很多索引需要更新時),而且它可能降低等待處理的SELECT陳述句的性能,
如果資料檢索是最重要的(通常是這樣),則你可以通過在
INSERT和INTO之間添加關鍵字LOW_PRIORITY,指示MySQL
降低INSERT陳述句的優先級,如下所示:
INSERT LOW_PRIORITY INTO
順便說一下,這也適用于下一章介紹的UPDATE和DELETE陳述句,
9 修改資料
UPDATE customers
SET cust_email = 'elmer@fudd.com'
WHERE cust_id = 10005;
10 洗掉資料
🔴 DELETE陳述句從表中洗掉行,甚至是洗掉表中所有行,但是,DELETE不洗掉表本身,
DELETE FROM customers
WHERE cust_id = 10005;
如果想從表中洗掉所有行,不要使用DELETE,可使用TRUNCATE TABLE陳述句,它完成相同的作業,但速度更快(TRUNCATE實際是洗掉原來的表并重新創建一個表,而不是逐行洗掉表中的資料),
11 MySQL引擎型別
MySQL與其他DBMS不一樣,它具有多種引擎,它打包多個引擎,這些引擎都隱藏在MySQL服務器內,全都能執行CREATE TABLE和SELECT等命令,
為什么要發行多種引擎呢?因為它們具有各自不同的功能和特性,
為不同的任務選擇正確的引擎能獲得良好的功能和靈活性,
以下是幾個需要知道的引擎:
- InnoDB是一個可靠的事務處理引擎,它不支持全文本搜索;
- MEMORY在功能等同于MyISAM,但由于資料存盤在記憶體(不是磁盤)中,速度很快(特別適合于臨時表);
- MyISAM是一個性能極高的引擎(往往是默認引擎),它支持全文本搜索,但不支持事務處理,
12 MySQL特性
| 特性 | 含義 |
|---|---|
| 原子性 | 一個事務中的所有操作,要么全部完成,要么全部不完成,如果事務程序中發生錯誤,會被回滾到開始的狀態, |
| 一致性 | 事務執行前后,資料庫的完整性沒有被破壞,這意味著寫入的所有資訊都要符合預設的規則, |
| 隔離性 | 資料庫允許多個并發事務同時進行讀寫和修改,隔離性可以放置多個事務并發執行時由于交叉執行導致資料不一致, |
| 持久性 | 事務處理結束后,對資料的修改是永久的,即使系統故障也不會丟失, |
13 視圖
13.1 什么是視圖?
🔴 視圖是虛擬的表,與包含資料的表不一樣,視圖只包含使用時動態檢索資料的查詢,
來看一個例子:
SELECT cust_name, cust_contact
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2'
此查詢用來檢索訂購了某個特定產品的客戶,任何需要這個資料的
人都必須理解相關表的結構,并且知道如何創建查詢和對表進行聯結,為了檢索其他產品(或多個產品)的相同資料,必須修改最后的WHERE子句,
現在,假如可以把整個查詢包裝成一個名為productcustomers的虛
擬表,則可以如下輕松地檢索出相同的資料:
SELECT cust_name, cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2'
這就是視圖的作用,productcustomers是一個視圖,作為視圖,它
不包含表中應該有的任何列或資料,它包含的是一個SQL查詢(與上面用
以正確聯結表的相同的查詢),
13.2 為什么使用視圖?
- 重用SQL陳述句,
- 簡化復雜的SQL操作,在撰寫查詢后,可以方便地重用它而不必
知道它的基本查詢細節, - 使用表的組成部分而不是整個表,
- 保護資料,可以給用戶授予表的特定部分的訪問權限而不是整個
表的訪問權限, - 更改資料格式和表示,視圖可回傳與底層表的表示和格式不同的
資料,
13.3 使用視圖
- 視圖不包含表中應該有的任何列或資料,只包含一個SQL查詢,
- 視圖使用CREATE VIEW陳述句來創建,
- SHOW CREATE VIEW viewname; 來查看創建視圖的陳述句,
- CREATE OR REPLACE VIEW來更新視圖,
CREATE VIEW productcustomers AS
SELECT cust_name, cust_contact, prod_id
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
- 以上視圖聯結了三個表,回傳了已經訂購任意產品的所有客戶的串列,
SELECT cust_name, cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
- 或者也可以使用視圖來重新格式化出檢索出來的資料,
CREATE VIEW vendorlocations AS
SELECT Concat(RTrim(vend_name), '(',RTrim(vend_country),')')
AS vend_title
FROM vendors
ORDER BY vend_name
14 匯出資料
代碼如下:
SELECT * FROM customers
INTO OUTFILE 'customers.txt'
FIELDS TERMINATED BY ',' ENCLOSED BY ''''
LINES TERMINATED BY '\r\n';
15 視窗函式
這個就是面試時的高頻考點啦,
以下資料來源begtut,
🔴 視窗函式的視窗表示范圍,可以理解為將原資料劃分范圍,也就是分組,然后用函式實作某些目的,相比于GROUP BY , 視窗函式不會減少原來的行數,
- 語法: SELECT 視窗函式 OVER (PARTITION BY 用于分組的列名 ORDER BY 用于排序的列)
- 專用視窗函式:rank(), dense_rank(), row_numer()
當然啦,那些聚合函式在這里要用也可以用,
SELECT *,
rank() over (PARTITION BY class_id ORDER BY SCORE DESC ) AS ranking
FROM class
15.1 rank()、dense_rank()和row_number()
三個函式的主要區別是如何處理并列情況:
- rank()中的并列情況會占用下一個名詞的位置, 1,1,1,4
- dense_rank() 不會占用下一個名詞 1,1,1,2
- row_number()中,會忽略并列的情況, 1,2,3,4
15.2 CUME_DIST()和PERCENT_RANK()
🔴 CUME_DIST()是一個視窗函式,它回傳一組值中值的累積分布,它表示值小于或等于行的值除以總行數的行數,重復的列值接收相同的CUME_DIST()值,計算的時候,取重復值的最后一行的位置,
SELECT name,
score,
ROW_NUMBER() OVER (ORDER BY score) row_num,
CUME_DIST() OVER (ORDER BY score) cume_dist_val
FROM scores;
輸出結果:
| name | score | row_num | cume_dist_val |
|---|---|---|---|
| Jones | 55 | 1 | 0.2 |
| Williams | 55 | 2 | 0.2 |
| Brown | 62 | 3 | 0.4 |
| Taylor | 62 | 4 | 0.4 |
| Thomas | 72 | 5 | 0.6 |
| Wilson | 72 | 6 | 0.6 |
| Smith | 81 | 7 | 0.7 |
| Davies | 84 | 8 | 0.8 |
| Evans | 87 | 9 | 0.9 |
| Johnson | 100 | 10 | 1 |
🔴 PERCENT_RANK()和CUME_DIST()一樣,是計算某個值在一組有序的資料中累計的分布,但不同在于計算分布結果的方法:(rank - 1) / (total_rows - 1),在此公式中,rank是指定行的等級,total_rows是要計算的行數,復的列值接收相同的CUME_DIST()值,計算的時候,取重復值的第一行的位,具體如下:
SELECT name,
score,
ROW_NUMBER() OVER (ORDER BY score) row_num,
PERCENT_RANK() OVER (ORDER BY score) cume_dist_val
FROM scores;
輸出結果:
| name | score | row_num | percent_rank_val |
|---|---|---|---|
| Jones | 55 | 1 | 0.2 |
| Williams | 55 | 2 | 0.2 |
| Brown | 62 | 3 | 0.4 |
| Taylor | 62 | 4 | 0.4 |
| Thomas | 72 | 5 | 0.6 |
| Wilson | 72 | 6 | 0.6 |
| Smith | 81 | 7 | 0.7 |
| Davies | 84 | 8 | 0.8 |
| Evans | 87 | 9 | 0.9 |
| Johnson | 100 | 10 | 1 |
15.3 FIRST_VALUE()和LAST_VALUE()
🔴 FIRST_VALUE()是一個視窗函式,允許您選擇視窗框架,磁區或結果集的第一行,
SELECT employee_name,
hours,
FIRST_VALUE(employee_name) OVER (
ORDER BY hours
) least_over_time
FROM overtime;
輸出結果:
| employee_name | hours | least_over_time |
|---|---|---|
| Steve Patterson | 29 | Steve Patterson |
| Diane Murphy | 37 | Steve Patterson |
| Jeff Firrelli | 40 | Steve Patterson |
| Gerard Bondur | 47 | Steve Patterson |
| Loui Bondur | 49 | Steve Patterson |
| William Patterson | 58 | Steve Patterson |
在此示例中,ORDER BY子句按結果集對行中的行進行了按小時排序,并FIRST_VALUE()選擇了第一行,表示加班時間最短的員工,
如果反過來想取加班時間最長的員工,則將FIRST_VALUE()改成LAST_VALUE()
15.4 LAG()和LEAD()
🔴 LAG()函式:從同一結果集中的當前行訪問上n行的資料,
語法:LAG(param1, param2, param3)
- param1 欄位名
- param2 前面第幾行
- param3 當前面第幾行沒有值時范圍的值,沒有設定的話就自動回傳NULL,
WITH productline_sales AS (
SELECT productline,
YEAR(orderDate) order_year,
ROUND(SUM(quantityOrdered * priceEach),0) order_value
FROM orders
INNER JOIN orderdetails USING (orderNumber)
INNER JOIN products USING (productCode)
GROUP BY productline, order_year
)
SELECT productline,
order_year,
order_value,
LAG(order_value, 1) OVER (
PARTITION BY productLine
ORDER BY order_year
) prev_year_order_value
FROM productline_sales;
輸出結果:
| productline | order_year | order_value | prev_year_order_value |
|---|---|---|---|
| Classic Cars | 2013 | 1374832 | NULL |
| Classic Cars | 2014 | 1763137 | 1374832 |
| Classic Cars | 2015 | 715954 | 1763137 |
| Motorcycles | 2013 | 348909 | NULL |
| Motorcycles | 2014 | 527244 | 348909 |
| Motorcycles | 2015 | 245273 | 527244 |
🔴 LEAD()函式:從同一結果集中的當前行訪問后n行的資料,
將上述代碼中的LAG函式改為LEAD函式,
此時的輸出結果:
| productline | order_year | order_value | prev_year_order_value |
|---|---|---|---|
| Classic Cars | 2013 | 1374832 | 1763137 |
| Classic Cars | 2014 | 1763137 | 715954 |
| Classic Cars | 2015 | 715954 | NULL |
| Motorcycles | 2013 | 348909 | 527244 |
| Motorcycles | 2014 | 527244 | 245273 |
| Motorcycles | 2015 | 245273 | NULL |
15.5 NTH_VALUE()
🔴 NTH_VALUE()是一個視窗函式,允許您從有序行集中的第N行獲取值,
SELECT employee_name,
salary,
NTH_VALUE(employee_name, 2) OVER (
ORDER BY salary DESC
) second_highest_salary
FROM basic_pays;
輸出結果:
| employee_name | salary | second_highest_salary |
|---|---|---|
| Larry Bott | 11798 | NULL |
| Gerard Bondur | 11472 | Gerard Bondur |
| Pamela Castillo | 11303 | Gerard Bondur |
| Barry Jones | 10586 | Gerard Bondur |
| George Vanauf | 10563 | Gerard Bondur |
15.6 NTILE()
🔴 NTILE()函式將排序磁區中的行劃分為特定數量的組,從每個組分配一個從一開始的桶號,對于每一行,NTILE()函式回傳一個桶號,表示行所屬的組,
SELECT val,
NTILE(4) OVER (
ORDER BY val
) group_no
FROM ntileDemo;
輸出結果:
| val | group_no |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 3 |
| 8 | 4 |
| 9 | 4 |
從輸出中可以看出,第一組有三行,而其他組有兩行,
也就是說,如果不平均,余n個資料,那排在前n的組就會各多一個,
學習更多資料分析技能和掌握實戰專案,可以關注我的資料分析專欄,
CSDN@報告,今天也有好好學習
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/297364.html
標籤:其他
上一篇:Redis+Nginx+設計模式+Spring全家桶+SQL+Dubbo技術好文精選整理
下一篇:博客反抄襲作業的一些思考和嘗試
