MySQL必知必會—檢索數據篇

MySQL必知必會—概念篇mysql

MySQL必知必會—安裝應用篇git

下面用到的數據庫文件可在 mysql_scripts 找到。


檢索數據

# 檢索單個列,例如從 products 表中檢索一個名爲 prod_name 的列。
SELECT prod_name FROM products;

# 檢索多個列。注意,列名之間要用逗號分隔,最後一個列名後不要加逗號,會報錯。
SELECT prod_id, prod_name, prod_price FROM products;

# 檢索全部列。
SELECT * FROM products;

# 只檢索出不一樣的行, DESTINCT 關鍵字可讓指令只返回不一樣的值。若是指令,products 表中可能一共有14行,如今只返回不一樣(惟一)的 vend_id 行,可能就只返回4行了。
SELECT DISTINCT vend_id FROM products;

# 限制結果, LIMIT 5 表示只返回很少於5行。
SELECT prod_name FROM products LIMIT 5;

# LIMIT 5, 5 表示返回從行5開始的5行。
SELECT prod_name FROM products LIMIT 5, 5;
# 或者使用 LIMIT 5 OFFSET 5, 跟上面結果相同。
SELECT prod_name FROM products LIMIT 5 OFFSET 5;

# 注意,返回行數是從 0 開始的。因此,LIMIT 1, 1 將檢索出第二行,而不是第一行。
SELECT prod_name FROM products LIMIT 1,1;
複製代碼


排序檢索數據 ( ORDER BY )

不使用排序時,其實檢索出的數據並非以純粹的隨機順序顯示的,數據通常將以它在底層表中出現的順序顯示。這能夠是數據最初添加到表中的順序,可是,若是數據後來進行過更新或者刪除,則此順序將會受到 MySQL 重用回收存儲空間的影響。所以,若是不明確控制的話,不能(也不該該)依賴該排序順序。github

關係數據庫設計理論認爲:若是不明確規定排序順序,則不該該假定檢索出的數據的順序有意義。正則表達式

ORDER BY 子句,能夠給 SELECT 語句檢索出來的數據進行排序。 ORDER BY 子句取一個或多個列的名字。據此對輸出進行排序。算法

# 沒有排序
SELECT prod_name FROM products;

# 對 prod_name 列以字母順序排序數據
SELECT prod_name FROM products ORDER BY prod_name;

# 按多個列排序:以下會先按照 prod_price 排序,
# 只有出現相同的 prod_price 時,纔會再按照 prod_name 排序。
SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price, prod_name;

# 指定排序方向,默認是升序,例如按照 prod_price 降序排序(最貴的排在最前面)
SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC;
# 多個列排序,例如按照 prod_price 降序,最貴的在最前面,而後在對產品名排序
SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC, prod_name;

# ORDER BY 和 LIMIT 搭配,能夠找出一個列中最高或最低的值。
SELECT prod_price FROM products ORDER BY prod_price DESC LIMIT 1;
複製代碼

注意:

  • ORDER BY 子句中使用的列不必定非得是檢索的列,用非檢索的列排序也是徹底合法的。
  • 若是想在多個列上進行降序排序,必須對每一個列指定 DESC 關鍵字。
  • ASC 是升序排序,升序是默認的,不指定 DESC ,那就是按照 ASC 升序排序。
  • ORDER BY 子句必須位於 FROM 子句以後,若是使用 LIMIT ,它必須位於 ORDER BY 以後。


過濾數據 ( WHERE )

數據庫包含大量的數據,可是咱們不多須要檢索表中全部的行。只檢索所需數據須要指定過濾條件,在 SELECT 語句中,數據根據 WHERE 子句中指定的搜索條件進行過濾。sql

# 檢索 pro_price 爲 2.50 的行
SELECT prod_name FROM products WHERE prod_price = 2.50;

# 執行篩選匹配時默認不區分大小寫,因此 fuses 能夠檢索出 Fuses
SELECT prod_name, prod_price FROM products WHERE prod_name = 'fuses';
# 輸出
+-----------+------------+
| prod_name | prod_price |
+-----------+------------+
| Fuses     |       3.42 |
+-----------+------------+

# 檢索出 vend_id 不等於 1003 的行
SELECT vend_id, prod_name FROM products WHERE vend_id <> 1003;

# 檢索 prod_price 在 5 到 10 之間的全部行
SELECT prod_name, prod_price FROM products WHERE prod_price BETWEEN 5 AND 10;

# 檢查具備 NULL 值的列,用 IS NULL 子句
SELECT cust_id FROM customers WHERE cust_email IS NULL;
複製代碼

WHERE 子句操做符

操做符 說明
= 等於
<> 不等於
!= 不等於
< 小於
<= 小於等於
> 大於
>= 大於等於
BETWEEN 在指定的兩個值之間

注意:

  • WHERE 語句的位置:在同時使用 ORDER BY 和 WHERE 子句時,應該讓 ORDER BY 位於 WHERE 以後,不然將會產生錯誤。
  • WHERE 子句中使用的條件,若是將值與串類型(例如字符串)比較,須要加引號,用來與數值列進行比較的值不用引號。
  • NULL 無值(no value),它與字段 0 、空字符串或僅僅包含空格不一樣。


數據過濾( AND、 OR、 IN )

MySQL 容許組合多個 WHERE 子句。這些子句分爲兩種方式使用:以 AND 子句的方式或 OR 子句的方式使用。數據庫

### AND 操做符
# 檢索出 vend_id 等於 1003 而且 prod_price 小於等於 10 的行
SELECT prod_price, prod_name FROM products WHERE vend_id = 1003 AND prod_price <= 10;


#### OR 操做符
# 檢索出 vend_id 等於 1002 或 vend_id 等於 1003 的全部行
SELECT prod_name, prod_price FROM products WHERE vend_id = 1002 OR vend_id = 1003;


# AND 和 OR 合用,AND 優先級高。
# 下面檢索出的結果是 vend_id 是 1003 而且 prod_price 大於等於 10 的和全部 vend_id 是 1002 的行。
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;
# 輸出結果
+---------+----------------+------------+
| vend_id | prod_name      | prod_price |
+---------+----------------+------------+
|    1002 | Fuses          |       3.42 |
|    1002 | Oil can        |       8.99 |
|    1003 | Detonator      |      13.00 |
|    1003 | Bird seed      |      10.00 |
|    1003 | Safe           |      50.00 |
|    1003 | TNT (5 sticks) |      10.00 |
+---------+----------------+------------+

# 若是想檢索出 vend_id 是 1003 而且 prod_price 大於等於 10 的和 vend_id 是 1002  而且 prod_price 大於等於 10 的行,須要加括號。
SELECT vend_id, prod_name, prod_price FROM products WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;


### IN 操做符,指定條件範圍,範圍中的每一個條件均可以進行匹配。IN 取值是所有括在圓括號中的由逗號分隔的列表。
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id IN (1002, 1003);


### NOT 操做符,否認它以後的任何條件
SELECT vend_id, prod_name, prod_price FROM products WHERE vend_id NOT IN (1002, 1003);
複製代碼

注意

  • WHERE 可包含任意數目的 AND 和 OR 操做符,而且容許二者結合以進行復雜和高效的過濾。不過 SQL 語言在處理 OR 操做符前,會優先處理 AND 操做符。
  • 任什麼時候候使用具備 AND 和 OR 操做符的 WHERE 子句, 都推薦使用圓括號明確地分組,不要過度依賴默認計算次序。
  • IN 和 OR 具備相同的功能,可是 IN 操做符有如下優勢
    • 過濾的字段太多的時候,IN 操做符的語法更清楚且更直觀
    • IN 操做符通常比 OR 操做符執行的更快
    • IN 最大的優勢是能夠包含其餘 SELECT 語句,能更動態地創建 WHERE 子句。
  • MySQL 支持使用 NOT 對 IN、BETWEEN 和 EXISTS 子句取反。


用通配符過濾

百分號(%)通配符

% 表示任何字符出現任意次數,可使0次,1次,n次數組

### 找出全部以 jet 開頭的產品
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE 'jet%';
+---------+--------------+
| prod_id | prod_name    |
+---------+--------------+
| JP1000  | JetPack 1000 |
| JP2000  | JetPack 2000 |
+---------+--------------+

### 通配符可在搜索模式中任意位置使用,而且可使用多個通配符。
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '%anvil%';
+---------+--------------+
| prod_id | prod_name    |
+---------+--------------+
| ANV01   | .5 ton anvil |
| ANV02   | 1 ton anvil  |
| ANV03   | 2 ton anvil  |
+---------+--------------+

複製代碼

下劃線通配符

下劃線 _ 只能匹配單個字符,只能匹配一個,不能多也不能少。數據庫設計

### 對比一下下面兩個通配符結果
SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '_ ton anvil';
+---------+-------------+
| prod_id | prod_name   |
+---------+-------------+
| ANV02   | 1 ton anvil |
| ANV03   | 2 ton anvil |
+---------+-------------+


SELECT prod_id, prod_name FROM products WHERE prod_name LIKE '% ton anvil';
+---------+--------------+
| prod_id | prod_name    |
+---------+--------------+
| ANV01   | .5 ton anvil |
| ANV02   | 1 ton anvil  |
| ANV03   | 2 ton anvil  |
+---------+--------------+

### 下劃線通配符比百分號通配符少了一個 .5 的數據
複製代碼

注意

  • 注意尾部空格,例如'%anvil' 是匹配不到 'anvil ',由於後面有個空格不容易發現,解決方法就是後面再附加一個 % ,或者用函數去掉首尾空格。
  • % 是不能匹配出 NULL的。
  • 通配符搜索的處理通常要比其餘搜索花時間更長,因此不要過分使用通配符,若是其餘操做符能達到一樣的目的,優先使用其餘操做符。在確實須要使用通配符時,除非絕對有必要,不然不要把他們用在搜索模式的開始處。


用正則表達式進行搜索

### 基本字符匹配,下面的語句檢索列 prod_name 包含文本 1000 的全部行。
SELECT prod_name FROM products WHERE prod_name REGEXP '1000' ORDER BY prod_name;

### 區分大小寫須要用到 BINARY 關鍵字
SELECT prod_name FROM products WHERE prod_name REGEXP BINARY 'S';

### 使用 | 進行 OR 匹配,能夠有兩個以上的 OR 條件,例如: '1000|2000|3000'
SELECT prod_name FROM products WHERE prod_name REGEXP '1000|2000';
+--------------+
| prod_name    |
+--------------+
| JetPack 1000 |
| JetPack 2000 |
+--------------+

### 匹配幾個字符之一
SELECT prod_name FROM products WHERE prod_name REGEXP '[1,2,3] Ton' ORDER BY prod_name;
+-------------+
| prod_name   |
+-------------+
| 1 ton anvil |
| 2 ton anvil |
+-------------+
### 注意區別 1|2|3 Ton,這表示匹配出 1,2和3 Ton,其實[123]是[1|2|3]的縮寫
SELECT prod_name FROM products WHERE prod_name REGEXP '1|2|3 Ton' ORDER BY prod_name;
+---------------+
| prod_name     |
+---------------+
| 1 ton anvil   |
| 2 ton anvil   |
| JetPack 1000  |
| JetPack 2000  |
| TNT (1 stick) |
+---------------+

### 匹配特殊字符, \\ 來轉義特殊字符
SELECT vend_name FROM vendors WHERE vend_name REGEXP '\\.' ORDER BY vend_name;
+--------------+
| vend_name    |
+--------------+
| Furball Inc. |
+--------------+


### 匹配出連在一塊兒的4個數字
SELECT prod_name FROM products WHERE prod_name REGEXP '[:digit:]{4}' ORDER BY prod_name;
+--------------+
| prod_name    |
+--------------+
| JetPack 1000 |
| JetPack 2000 |
+--------------+
複製代碼

列舉元字符轉義和定位元字符

元字符 說明
\f 換頁
\n 換行
\r 回車
\t 製表
\v 縱向製表
\\ 反斜槓
^ 文本的開始
$ 文本的結束
[[:<:]](8版本以後改成 \b) 詞的開始
[[:>:]](8版本以後改成 \b) 詞的結束

多數正則表達式實現使用單個反斜槓轉義特殊字符,以便能使用這些字符自己。但 MySQL 要求兩個反斜槓(MySQL本身解釋一個,正則表達式庫解釋另外一個)。函數

列舉字符類

說明
[:alnum:] 任意字符和數字(同 [a-zA-Z0-9])
[:alpha:] 任意字符(同 [a-zA-Z])
[:blank:] 空格和製表 (同 [\t])
[:cntrl:] ASCII控制字符 (ASCII 0 到 31 和 127)
[:digit:] 任意數字 (同 [0-9])
[:xdigit:] 任意十六進制數字(同 [a-fA-F0-9])
[:lower:] 任意小寫字母 (同 [a-z])
[:upper:] 任意大寫字母(同 [A-Z])
[:print:] 任意可打印字符
[:graph:] 與[:print:]相同,但不包含空格
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在內的任意空白字符(同 [\f\n\r\t\v])

簡單的正則表達式測試

在不使用數據庫表的狀況下用 SELECT 來測試正則表達式。 REGEXP 檢查老是返回0(沒有匹配)或 1(匹配)。

SELECT 'hello' REGEXP 'hello\\b';
+---------------------------+
| 'hello' REGEXP 'hello\\b' |
+---------------------------+
|                         1 |
+---------------------------+
複製代碼


計算字段

### 將查出來的名字和國家拼接出來展現,使用了 Concat、Trim函數,和 AS 關鍵字
SELECT Concat( Trim(vend_name), '(', Trim(vend_country), ')') AS vend_name FROM vendors ORDER BY vend_name;
+------------------------+
| vend_name              |
+------------------------+
| ACME(USA)              |
| Anvils R Us(USA)       |
| Furball Inc.(USA)      |
| Jet Set(England)       |
| Jouets Et Ours(France) |
| LT Supplies(USA)       |
+------------------------+


### 將20005訂單中的全部物品查出來,經過數量和單價算出總價
SELECT prod_id, quantity, item_price, quantity*item_price AS expanded_price FROM orderitems WHERE order_num = 20005;
+---------+----------+------------+----------------+
| prod_id | quantity | item_price | expanded_price |
+---------+----------+------------+----------------+
| ANV01   |       10 |       5.99 |          59.90 |
| ANV02   |        3 |       9.99 |          29.97 |
| TNT2    |        5 |      10.00 |          50.00 |
| FB      |        1 |      10.00 |          10.00 |
+---------+----------+------------+----------------+
複製代碼

測試計算

SELECT 提供了測試和實驗函數與計算的一個很好的方法,就是省略 FROM 子句

SELECT 3*2;
+-----+
| 3*2 |
+-----+
|   6 |
+-----+

SELECT Now();
+---------------------+
| Now()               |
+---------------------+
| 2019-11-21 22:51:13 |
+---------------------+
複製代碼


使用數據處理函數

函數沒有 SQL 的可移植性強,幾乎每種主要的 DBMS 的實現都支持其餘實現不支持的函數,有時差別還很大。爲了代碼的可移植性,不少人不同意使用特殊實現的功能,雖然這樣作頗有好處,可是對於應用程序的性能可能出現影響。若是決定使用函數,應該保證作好代碼註釋。

文本處理函數

函 數 說 明
Left() 返回串左邊的字符
Length() 返回串的長度
Locate() 找出串的一個子串
Lower() 將串轉換爲小寫
LTrim() 去掉串左邊的空格
Right() 返回串右邊的字符
RTrim() 去掉串右邊的空格
Soundex() 返回串的 SOUNDEX 值
SubString() 返回子串的字符
Upper() 將串轉換爲大寫

SOUNDEX 是一個將任何文本串轉換爲描述其語音表示的字母數字模式的算法。SOUNDEX 考慮了相似的發音字節和音節,使得能對串進行發音比較而不是字母比較。

### 例如用 Y. Lie 把 Y Lee 搜出來,由於它們發音相似
SELECT cust_name, cust_contact FROM customers WHERE Soundex(cust_contact) = Soundex('Y. Lie');
+-------------+--------------+
| cust_name   | cust_contact |
+-------------+--------------+
| Coyote Inc. | Y Lee        |
+-------------+--------------+
複製代碼

日期和時間處理函數

函 數 說 明
AddDate() 增長一個日期(天、周等)
AddTime() 增長一個時間(時、分等)
CurDate() 返回當前日期
CurTime() 返回當前時間
Date() 返回日期時間的日期部分
DateDiff() 計算兩個日期之差
Date_Add() 高度靈活的日期運算函數
Date_Format() 返回一個格式化的日期或時間串
Year() 返回一個日期的年份部分
Month() 返回一個日期的月份部分
Day() 返回一個日期的天數部分
DayOfWeek() 對於一個日期,返回對應的星期幾
Hour() 返回一個時間的小時部分
Minute() 返回一個時間的分鐘部分
Second() 返回一個時間的秒部分
Now() 返回當前日期和時間
### 檢索出日期爲 2005-09-01 這天的訂單記錄
SELECT cust_id, order_num FROM orders WHERE order_date = '2005-09-01';


### 上面的檢索有個問題,若是 order_date 存儲的帶有時間,例如 2005-09-01 11:30:05 ,就檢索不到了,解決辦法是讓僅將給出的日期與列中的日期部分進行比較
SELECT cust_id, order_num FROM orders WHERE Date(order_date) = '2005-09-01';

### 若是想檢索出2005年9月的全部訂單

### 方法一,得記住每月有多少天,甚至要知道是否是閏年的2月
SELECT cust_id, order_num FROM orders WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30';

### 方法二, 使用 Year() 和 Month() 函數
SELECT cust_id, order_num FROM orders WHERE Year(order_date) = 2005 AND Month(order_date) = 9;

複製代碼

注意

  • 使用日期過濾,日期必須爲 yyyy-mm-dd ,這樣能排除一些歧義,年份也應該使用4位數字,更加可靠。

數值處理函數

函 數 說 明
Abs() 返回一個數的絕對值
Sin() 返回一個角度的正弦
Cos() 返回一個角度的餘弦
Tan() 返回一個角度的正切
Exp() 返回一個數的指數值
Mod() 返回除操做的餘數
Pi() 返回圓周率
Rand() 返回一個隨機數
Sqrt() 返回一個數的平方根


彙總數據

函 數 說 明
AVG() 返回某列的平均值
COUNT() 返回某列的行數
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和
### 計算出 products 表中全部產品的平均價格
SELECT AVG(prod_price) AS avg_price FROM products;
+-----------+
| avg_price |
+-----------+
| 16.133571 |
+-----------+

### 查看 customers 表中全部客戶的總數
SELECT COUNT(*) AS num_cust FROM customers;
+----------+
| num_cust |
+----------+
|        5 |
+----------+
### 只對具備電子郵件地址的客戶計數
SELECT COUNT(cust_email) AS num_cust FROM customers;
+----------+
| num_cust |
+----------+
|        3 |
+----------+

### 計算出訂單號爲 20005 的物品總數
SELECT SUM(quantity) AS items_ordered FROM orderitems WHERE order_num = 20005;
+---------------+
| items_ordered |
+---------------+
|            19 |
+---------------+

### 多個彙集函數組合
SELECT COUNT(*) AS num_items, MIN(prod_price) AS price_min, MAX(prod_price) AS price_max, AVG(prod_price) AS price_avg FROM products;
+-----------+-----------+-----------+-----------+
| num_items | price_min | price_max | price_avg |
+-----------+-----------+-----------+-----------+
|        14 |      2.50 |     55.00 | 16.133571 |
+-----------+-----------+-----------+-----------+
複製代碼

參數 ALL 和 DISTINCT

使用 DISTINCT 參數時,只會計算包含不一樣的值的行,若是指定參數爲 ALL 或者不指定參數,默認參數爲 ALL ,會計算全部的行。

### 看一下產品表裏有多少家供應商,由於有可能一家供應商提供不少產品。
### 所有的行
SELECT COUNT(vend_id) AS vend_count FROM products;
+------------+
| vend_count |
+------------+
|         14 |
+------------+
### 去重後就知道有 4 家供應商
SELECT COUNT(DISTINCT vend_id) AS vend_count FROM products;
+------------+
| vend_count |
+------------+
|          4 |
+------------+
複製代碼

注意

  • AVG() 只能用來肯定 單個 特定數值列的平均值,並且列名必須做爲函數參數傳入,想獲取多個列的平均值,必須使用多個 AVG() 函數。
  • AVG() 函數忽略列值爲 NULL 的行。
  • COUNT(*) 對錶中行的數目進行計數, 無論列中是空值(NULL)仍是非空值。
  • 使用 COUNT(column) 對特定列中具備值的行進行計數,會忽略 NULL 值。
  • MAX() 函數會忽略值爲 NULL 的行(MIN()也是)。它通常是用來找出最大的數值和日期值,可是也能夠對非數值的數據使用,例如返回文本列中的最大值,MAX() 會返回最後一行(MIN () 會返回第一行)。
  • SUM() 函數會忽略值爲 NULL 的行
  • 在表示某個彙集函數的結果時,不該該使用表中實際的列明,最好是指定別名,這樣便於理解和使用。


分組數據

數據分組

SELECT vend_id, prod_price FROM products GROUP BY vend_id, prod_price;
複製代碼
  • GROUP BY 子句後面能夠加多個列。
  • SELECT子句中的列名必須爲分組列或列函數(彙集計算語句除外),例如 按照 vend_id, prod_price 分組,SELECT 後面檢索的列必須是 vend_id, prod_price。
  • 列函數對於GROUP BY子句定義的每一個組各返回一個結果,例如取最大值時,就是每一個組的最大值。
  • 若是分組列中有 NULL 值,則 NULL 將做爲一個分組返回,若是列中有多行 NULL 值,它們將分爲一組。
  • GROUP BY 子句必須在 WHERE 子句以後, ORDER BY 子句以前。

過濾分組

### 列出至少有兩個訂單的全部顧客
SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2;

### 列出具備2個(含)以上、價格爲10(含)以上的產品的供應商
SELECT vend_id, COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2;

### 列出總計訂單價格大於等於50的訂單,並按照總價排序
SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50 ORDER BY ordertotal;
+-----------+------------+
| order_num | ordertotal |
+-----------+------------+
|     20006 |      55.00 |
|     20008 |     125.00 |
|     20005 |     149.87 |
|     20007 |    1000.00 |
+-----------+------------+
複製代碼
  • HAVING 跟 WHERE 相似,可是 WHERE 在數據分組前進行過濾,HAVING 在數據分組後進行過濾。


SELECT 子句順序

SELECT > FROM > WHERE > GROUP BY > HAVING > ORDER BY > LIMIT


一個持續更新的github筆記,連接地址:Front-End-Basics,能夠watch,也能夠star。

此篇文章的地址:MySql必知必會

相關文章
相關標籤/搜索