# DQL-MySQL資料查詢SQL
文法格式:
```mysql
select 字段清單|* from 表名
[where 搜尋條件]
[group by 分組字段 [having 分組條件]]
[order by 排序字段 排序規則]
[limit 分頁參數]
```
### 基礎查詢
```mysql
# 查詢表中所有列 所有資料
select * from users;
# 指定字段清單進行查詢
select id,name,phone from users;
```
### Where 條件查詢
+ 可以在where子句中指定任何條件
+ 可以使用 and 或者 or 指定一個或多個條件
+ where條件也可以運用在update和delete語句的後面
+ where子句類似程式語言中if條件,根據mysql表中的字段值來進行資料的過濾
示例:
```mysql
-- 查詢users表中 age > 22的資料
select * from users where age > 22;
-- 查詢 users 表中 name=某個條件值 的資料
select * from users where name = '王五';
-- 查詢 users 表中 年齡在22到25之間的資料
select * from users where age >= 22 and age <= 25;
select * from users where age between 22 and 25;
-- 查詢 users 表中 年齡不在22到25之間的資料
select * from users where age < 22 or age > 25;
select * from users where age not between 22 and 25;
-- 查詢 users 表中 年齡在22到25之間的女生資訊
select * from users where age >= 22 and age <= 25 and sex = '女';
```
#### and和or 使用時注意
假設要求 查詢 users 表中 年齡為22或者25 的女生資訊
select * from users where age=22 or age = 25 and sex = '女';
思考上面的語句能否傳回符合條件的資料?
實際查詢結果并不符合要求?
```mysql
select * from users where age=22 or age = 25 and sex = '女';
+------+--------+------+-------+-------+------+------+
| id | name | age | phone | email | sex | mm |
+------+--------+------+-------+-------+------+------+
| 1 | 章三 | 22 | | NULL | 男 | 0 |
| 1002 | cc | 25 | 123 | NULL | 女 | NULL |
+------+--------+------+-------+-------+------+------+
2 rows in set (0.00 sec)
-- 上面的查詢結果并不符合 查詢條件的要求。
-- 問題出在 sql 計算的順序上,sql會優先處理and條件,是以上面的sql語句就變成了
-- 查詢變成了為年齡22的不管性别,或者年齡為 25的女生
-- 如何改造sql符合我們的查詢條件呢?
-- 使用小括号來關聯相同的條件
select * from users where (age=22 or age = 25) and sex = '女';
+------+------+------+-------+-------+------+------+
| id | name | age | phone | email | sex | mm |
+------+------+------+-------+-------+------+------+
| 1002 | cc | 25 | 123 | NULL | 女 | NULL |
+------+------+------+-------+-------+------+------+
1 row in set (0.00 sec)
```
#### Like 子句
> 我們可以在where條件中使用=,<,> 等符合進行條件的過濾,但是當想查詢某個字段是否包含時如何過濾?
>
> 可以使用like語句進行某個字段的模糊搜尋,
>
> 例如: 查詢 name字段中包含五的資料
```mysql
-- like 語句 like某個确定的值 和。where name = '王五' 是一樣
select * from users where name like '王五';
+----+--------+------+-------+-----------+------+------+
| id | name | age | phone | email | sex | mm |
+----+--------+------+-------+-----------+------+------+
| 5 | 王五 | 24 | 10011 | [email protected] | 男 | 0 |
+----+--------+------+-------+-----------+------+------+
1 row in set (0.00 sec)
-- 使用 % 模糊搜尋。%代表任意個任意字元
-- 查詢name字段中包含五的
select * from users where name like '%五%';
-- 查詢name字段中最後一個字元 為 五的
select * from users where name like '%五';
-- 查詢name字段中第一個字元 為 王 的
select * from users where name like '王%';
-- 使用 _ 單個的下劃線。表示一個任意字元,使用和%類似
-- 查詢表中 name 字段為兩個字元的資料
select * from users where name like '__';
-- 查詢 name 字段最後為五,的兩個字元的資料
select * from users where name like '_五';
```
**注意:where子句中的like在使用%或者_進行模糊搜尋時,效率不高,使用時注意:**
+ 盡可能的不去使用%或者_
+ 如果需要使用,也盡可能不要把通配符放在開頭處
### Mysql中的統計函數(聚合函數)
max(),min(),count(),sum(),avg()
```mysql
# 計算 users 表中 最大年齡,最小年齡,年齡和及平均年齡
select max(age),min(age),sum(age),avg(age) from users;
+----------+----------+----------+----------+
| max(age) | min(age) | sum(age) | avg(age) |
+----------+----------+----------+----------+
| 28 | 20 | 202 | 22.4444 |
+----------+----------+----------+----------+
-- 上面資料中的列都是在查詢時使用的函數名,不友善閱讀和後期的調用,可以通過别名方式 美化
select max(age) as max_age,
min(age) min_age,sum(age) as sum_age,
avg(age) as avg_age
from users;
+---------+---------+---------+---------+
| max_age | min_age | sum_age | avg_age |
+---------+---------+---------+---------+
| 28 | 20 | 202 | 22.4444 |
+---------+---------+---------+---------+
-- 統計 users 表中的資料量
select count(*) from users;
+----------+
| count(*) |
+----------+
| 9 |
+----------+
select count(id) from users;
+-----------+
| count(id) |
+-----------+
| 9 |
+-----------+
-- 上面的兩個統計,分别使用了 count(*) 和 count(id),結果目前都一樣,有什麼差別?
-- count(*) 是按照 users表中所有的列進行資料的統計,隻要其中一列上有資料,就可以計算
-- count(id) 是按照指定的 id 字段進行統計,也可以使用别的字段進行統計,
-- 但是注意,如果指定的列上出現了NULL值,那麼為NULL的這個資料不會被統計
-- 假設有下面這樣的一張表需要統計
+------+-----------+------+--------+-----------+------+------+
| id | name | age | phone | email | sex | mm |
+------+-----------+------+--------+-----------+------+------+
| 1 | 章三 | 22 | | NULL | 男 | 0 |
| 2 | 李四 | 20 | | NULL | 女 | 0 |
| 5 | 王五 | 24 | 10011 | [email protected] | 男 | 0 |
| 1000 | aa | 20 | 123 | NULL | 女 | NULL |
| 1001 | bb | 20 | 123456 | NULL | 女 | NULL |
| 1002 | cc | 25 | 123 | NULL | 女 | NULL |
| 1003 | dd | 20 | 456 | NULL | 女 | NULL |
| 1004 | ff | 28 | 789 | NULL | 男 | NULL |
| 1005 | 王五六 | 23 | 890 | NULL | NULL | NULL |
+------+-----------+------+--------+-----------+------+------+
9 rows in set (0.00 sec)
-- 如果按照sex這一列進行統計,結果就是8個而不是9個,因為sex這一列中有NULL值存在
mysql> select count(sex) from users;
+------------+
| count(sex) |
+------------+
| 8 |
+------------+
```
**聚合函數除了以上簡單的使用意外,通常情況下都是配合着分組進行資料的統計和計算**
### Group BY 分組
> group by 語句根據一個或多個列對結果集進行分組
>
> 一般情況下,是用與資料的統計或計算,配合聚合函數使用
```mysql
-- 統計 users 表中 男女生人數,
-- 很明顯按照上面的需要,可以寫出兩個語句進行分别統計
select count(*) from users where sex = '女';
select count(*) from users where sex = '男';
-- 可以使用分組進行統計,更友善
select sex,count(*) from users group by sex;
+------+----------+
| sex | count(*) |
+------+----------+
| 男 | 4 |
| 女 | 5 |
+------+----------+
-- 統計1班和2班的人數
select classid,count(*) from users group by classid;
+---------+----------+
| classid | count(*) |
+---------+----------+
| 1 | 5 |
| 2 | 4 |
+---------+----------+
-- 分别統計每個班級的男女生人數
select classid,sex,count(*) as num from users group by classid,sex;
+---------+------+-----+
| classid | sex | num |
+---------+------+-----+
| 1 | 男 | 2 |
| 1 | 女 | 3 |
| 2 | 男 | 2 |
| 2 | 女 | 2 |
+---------+------+-----+
# 注意,在使用。group by分組時,一般除了聚合函數,其它在select後面出現的字段列都需要出現在grouop by 後面
```
Having 子句
> having時在分組聚合計算後,對結果再一次進行過濾,類似于where,
>
> where過濾的是行資料,having過濾的是分組資料
```mysql
-- 要統計班級人數
select classid,count(*) from users group by classid;
-- 統計班級人數,并且要人數達到5人及以上
select classid,count(*) as num from users group by classid having num >=5;
```
### Order by 排序
> 我們在mysql中使用select的語句查詢的資料結果是根據資料在底層檔案的結構來排序的,
>
> 首先不要依賴預設的排序,另外在需要排序時要使用orderby對傳回的結果進行排序
>
> Asc 升序,預設
>
> desc降序
```mysql
-- 按照年齡對結果進行排序,從大到小
select * from users order by age desc;
-- 從小到大排序 asc 預設就是。可以不寫
select * from users order by age;
-- 也可以按照多個字段進行排序
select * from users order by age,id; # 先按照age進行排序,age相同情況下,按照id進行排序
select * from users order by age,id desc;
```
### Limit 資料分頁
+ limit n 提取n條資料,
+ limit m,n 跳過m跳資料,提取n條資料
```mysql
-- 查詢users表中的資料,隻要3條
select * from users limit 3;
-- 跳過前4條資料,再取3條資料
select * from users limit 4,3;
-- limit一般應用在資料分頁上面
-- 例如每頁顯示10條資料,第三頁的 limit應該怎麼寫? 思考
第一頁 limit 0,10
第二頁 limit 10,10
第三頁 limit 20,10
第四頁 limit 30,10
-- 提取 user表中 年齡最大的三個使用者資料 怎麼查詢?
select * from users order by age desc limit 3;
```
#### 課後練習題
```mysql
-- 1. 統計班級 classid為2的男女生人數?
-- 2. 擷取每個班級的 平均年齡,并按照平均年齡從大到小排序
-- 3. 統計每個班級的人數,按照從大到小排序
-- 4. 擷取班級人數最多的 班級id資訊
```
### 總結:
> mysql中的查詢語句比較靈活多樣,是以需要多加練習,
>
> 并且在使用查詢語句時,一定要注意sql的正确性和順序
| 子句 | 說明 | 是否必須 |
| -------- | -------------------------------- | ------------------ |
| select | 要傳回的列或表達式,字段清單\| * | 是 |
| from | 查詢的資料表 | 需要在表中查詢時 |
| Where | 資料行的過濾 | 否 |
| group by | 分組 | 僅在分組聚合計算時 |
| having | 分組後的資料過濾 | 否 |
| order by | 輸出排序 | 否 |
| limit | 要提取的結果行數 | 否 |