表(修改、排序、分頁、表關聯)
where子句(條件查詢):按照“條件表示式”指定的條件進行查詢。
group by子句(分組):按照“屬性名”指定的欄位進行分組。group by子句通常和count()、sum()等聚合函式一起使用。
having子句(篩選):有group by才能having子句,只有滿足“條件表示式”中指定的條件的才能夠輸出。
order by子句(排序):按照“屬性名”指定的欄位進行排序。排序方式由“asc”和“desc”兩個引數指出,預設是按照“asc”來排序,即升序。
limit(限制結果集)。
mysql中五種常用的聚合函式:
(1)max(列名):求最大值。
(2)min(列名):求最小值。
(2)sum(列名):求和。
(4)avg(列名):求平均值。
(5)count(列名):統計記錄的條數。
為了方便檢視資料,可以對資料進行排序
語法:order by 欄位 asc 或者 desc
說明 按照某欄位正序,倒序使用desc
將行資料按照列1進行排序,如果某些行列1的值相同時,則按照列2排序,以此類推
預設按照列值從小到大排列(asc)
asc從小到大排列,即升序
desc從大到小排序,即降序
例1:查詢學生資訊,按學號降序
select * from student order by id desc
例2:查詢學生資訊,按名稱升序
select * from student order by name asc
例3:顯示所有的學生資訊,先按照年齡從大-->小排序,當年齡相同時 按照身高從高-->矮排序
select * from student order by age desc,height desc
聚合函式
1、count函式
①count(*):返回表中滿足
mysql> select count(*) from salary_tab where salary='1000';
+----------+
| count(*) |
+----------+
| 2 |
+----------+
mysql> select count(*) from salary_tab; #沒有條件,預設統計表資料行數
+----------+
| count(*) |
+----------+
| 5 |
+----------+
②count(列):返回列值非空的行的數量
mysql> select count(salary) from salary_tab;
+---------------+
| count(salary) |
+---------------+
| 4 |
+---------------+
③count(distinct 列):返回列值非空的、並且列值不重複的行的數量
mysql> select count(distinct salary) from salary_tab;
+------------------------+
| count(distinct salary) |
+------------------------+
| 3 |
+------------------------+
④count(expr):根據表示式統計資料
mysql> select * from TT;
+------+------------+
| UNIT | DATE |
+------+------------+
| a | 2018-04-03 |
| a | 2017-12-12 |
| b | 2018-01-01 |
| b | 2018-04-03 |
| c | 2016-06-06 |
| d | 2018-03-03 |
+------+------------+
6 rows in set (0.00 sec)
mysql> select UNIT as '單位',
-> COUNT(TO_DAYS(DATE)=TO_DAYS(NOW()) or null) as '今日統計',
-> COUNT(YEAR(DATE)=YEAR(NOW()) or null) as '今年統計'
-> from v_jjd
-> group by JJDW;
+------+----------+----------+
| 單位 | 今日統計 | 今年統計 |
+------+----------+----------+
| a | 1 | 1 |
| b | 1 | 2 |
| c | 0 | 0 |
| d | 0 | 1 |
+------+----------+----------+
4 rows in set (0.00 sec)
2、max和min函式---統計列中的最大最小值
mysql> select max(salary) from salary_tab;
+-------------+
| max(salary) |
+-------------+
| 3000.00 |
+-------------+
mysql> select min(salary) from salary_tab;
+-------------+
| min(salary) |
+-------------+
| 1000.00 |
+-------------+
注意:如果統計的列中只有NULL值,那麼MAX和MIN就返回NULL
3、sum和avg函式---求和與求平均
!!表中列值為null的行不參與計算
mysql> select sum(salary) from salary_tab;
+-------------+
| sum(salary) |
+-------------+
| 7000.00 |
+-------------+
mysql> select avg(salary) from salary_tab;
+-------------+
| avg(salary) |
+-------------+
| 1750.000000 |
+-------------+
mysql> select avg(ifnull(salary,0)) from salary_tab;
+-----------------------+
| avg(ifnull(salary,0)) |
+-----------------------+
| 1400.000000 |
+-----------------------+
注意:要想列值為NULL的行也參與組函式的計算,必須使用IFNULL函式對NULL值做轉換。
二、分組SELECT
SELECT select_expr [, select_expr ...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
分組SELECT的基本格式:
select [聚合函式] 欄位名 from 表名
[where 查詢條件]
[group by 欄位名]
[having 過濾條件]
1、group by子句
根據給定列或者表示式的每一個不同的值將表中的行分成不同的組,使用組函式返回每一組的統計資訊
規則:
①出現在SELECT子句中的單獨的列,必須出現在GROUP BY子句中作為分組列
②分組列可以不出現在SELECT子句中
③分組列可出現在SELECT子句中的一個複合表示式中
④如果GROUP BY後面是一個複合表示式,那麼在SELECT子句中,它必須整體作為一個表示式的一部分才能使用。
1)指定一個列進行分組
mysql> select salary,count(*) from salary_tab
-> where salary>=2000
-> group by salary;
+---------+----------+
| salary | count(*) |
+---------+----------+
| 2000.00 | 1 |
| 3000.00 | 1 |
+---------+----------+
2)指定多個分組列,‘大組中再分小組’
mysql> select userid,count(salary) from salary_tab
-> where salary>=2000
-> group by salary,userid;
+--------+---------------+
| userid | count(salary) |
+--------+---------------+
| 2 | 1 |
| 3 | 1 |
+--------+---------------+
3)根據表示式分組
mysql> select year(payment_date),count(*)
-> from PENALTIES
-> group by year(payment_date);
+--------------------+----------+
| year(payment_date) | count(*) |
+--------------------+----------+
| 1980 | 3 |
| 1981 | 1 |
| 1982 | 1 |
| 1983 | 1 |
| 1984 | 2 |
+--------------------+----------+
5 rows in set (0.00 sec)
4)帶有排序的分組:如果分組列和排序列相同,則可以合併group by和order by子句
mysql> select teamno,count(*)
-> from MATCHES
-> group by teamno
-> order by teamno desc;
+--------+----------+
| teamno | count(*) |
+--------+----------+
| 2 | 5 |
| 1 | 8 |
+--------+----------+
2 rows in set (0.00 sec)
mysql> select teamno,count(*)
-> from MATCHES
-> group by teamno desc; #可以把desc(或者asc)包含到group by子句中簡化
+--------+----------+
| teamno | count(*) |
+--------+----------+
| 2 | 5 |
| 1 | 8 |
+--------+----------+
2 rows in set (0.00 sec)
對於分組聚合注意:
通過select在返回集欄位中,這些欄位要麼就要包含在group by語句後面,作為分組的依據,要麼就要被包含在聚合函式中。我們可以將group by操作想象成如下的一個過程:首先系統根據select語句得到一個結果集,然後根據分組欄位,將具有相同分組欄位的記錄歸併成了一條記錄。這個時候剩下的那些不存在與group by語句後面作為分組依據的欄位就很有可能出現多個值,但是目前一種分組情況只有一條記錄,一個數據格是無法放入多個數值的,所以這個時候就需要通過一定的處理將這些多值的列轉化成單值,然後將其放在對應的資料格中,那麼完成這個步驟的就是前面講到的聚合函式,這也就是為什麼這些函式叫聚合函數了。
2、GROUP_CONCAT()函式
函式的值等於屬於一個組的指定列的所有值,以逗號隔開,並且以字串表示。
例1:對於每個球隊,得到其編號和所有球員的編號
mysql> select teamno,group_concat(playerno)
-> from MATCHES
-> group by teamno;
+--------+------------------------+
| teamno | group_concat(playerno) |
+--------+------------------------+
| 1 | 6,6,6,44,83,2,57,8 |
| 2 | 27,104,112,112,8 |
+--------+------------------------+
2 rows in set (0.01 sec)
如果沒有group by子句,group_concat返回一列的所有值
例2:得到所有的罰款編號列表
mysql> select group_concat(paymentno)
-> from PENALTIES;
+-------------------------+
| group_concat(paymentno) |
+-------------------------+
| 1,2,3,4,5,6,7,8 |
+-------------------------+
1 row in set (0.00 sec)
3、with rollup子句:用來要求在一條group by子句中進行多個不同的分組
用的比較少點,但是有時可以根據具體的需求使用
如果有子句GROUP BY E1,E2,E3,E4 WITH ROLLUP
那麼將分別執行以下分組:[E1,E2,E3,E4]、[E1,E2,E3]、[E1,E2]、[E1]、[]
注意:[ ]表示所有行都分在一組中
示例:按照球員的性別和居住城市,統計球員的總數;統計每個性別球員的總數;統計所有球員的總數
mysql> select sex,town,count(*)
-> from PLAYERS
-> group by sex,town with rollup;
+-----+-----------+----------+
| sex | town | count(*) |
+-----+-----------+----------+
| F | Eltham | 2 |
| F | Inglewood | 1 |
| F | Midhurst | 1 |
| F | Plymouth | 1 |
| F | NULL | 5 |
| M | Douglas | 1 |
| M | Inglewood | 1 |
| M | Stratford | 7 |
| M | NULL | 9 |
| NULL | NULL | 14 |
+-----+-----------+----------+
10 rows in set (0.00 sec)
4、HAVING子句:對分組結果進行過濾
注意:
不能使用WHERE子句對分組後的結果進行過濾
不能在WHERE子句中使用組函式,僅用於過濾行
mysql> select playerno
-> from PENALTIES
-> where count(*)>1
-> group by playerno;
ERROR 1111 (HY000): Invalid use of group function
因為WHERE子句比GROUP BY先執行,而組函式必須在分完組之後才執行,且分完組後必須使用having子句進行結果集的過濾。
基本語法:
SELECT select_expr [, select_expr ...]
FROM table_name
[WHERE where_condition]
[GROUP BY {col_name | expr} [ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
!!!having子語句與where子語句區別:
where子句在分組前對記錄進行過濾;
having子句在分組後對記錄進行過濾
mysql> select salary,count(*) from salary_tab
-> where salary>=2000
-> group by salary
-> having count(*)>=0;
+---------+----------+
| salary | count(*) |
+---------+----------+
| 2000.00 | 1 |
| 3000.00 | 1 |
+---------+----------+
1)HAVING可以單獨使用而不和GROUP BY配合,如果只有HAVING子句而沒有GROUP BY,表中所有的行分為一組
2)HAVING子句中可以使用組函式
3)HAVING子句中的列,要麼出現在一個組函式中,要麼出現在GROUP BY子句中(否則出錯)
mysql> select town,count(*)
-> from PLAYERS
-> group by town
-> having birth_date>'1970-01-01';
ERROR 1054 (42S22): Unknown column 'birth_date' in 'having clause'
mysql> select town,count(*)
-> from PLAYERS
-> group by town
-> having town in ('Eltham','Midhurst');
+----------+----------+
| town | count(*) |
+----------+----------+
| Eltham | 2 |
| Midhurst | 1 |
+----------+----------+
2 rows in set (0.00 sec)
limit 分段取值
語法 limi m,n
m為其實位置,n為取幾個
select * from student limit 0,2
從第一個開始取,取兩個,如果不寫第一個引數,就是預設從第一個引數取值,取n個
select * from student limit 2
連線查詢(join 語法)
join 用於多表中欄位之間的聯絡,語法如下:
... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona
table1:左表;table2:右表。
JOIN 按照功能大致分為如下三類:
INNER JOIN(內連線,或等值連線):取得兩個表中存在連線匹配關係的記錄。
LEFT JOIN(左連線):取得左表(table1)完全記錄,即是右表(table2)並無對應匹配記錄。
RIGHT JOIN(右連線):與 LEFT JOIN 相反,取得右表(table2)完全記錄,即是左表(table1)並無匹配對應記錄。
注意:mysql不支援Full join,不過可以通過UNION 關鍵字來合併 LEFT JOIN 與 RIGHT JOIN來模擬FULL join.
接下來給出一個列子用於解釋下面幾種分類。如下兩個表(A,B)
- mysql> select A.id,A.name,B.name from A,B where A.id=B.id;
- +----+-----------+-------------+
- | id | name | name |
- +----+-----------+-------------+
- | 1 | Pirate | Rutabaga |
- | 2 | Monkey | Pirate |
- | 3 | Ninja | Darth Vader |
- | 4 | Spaghetti | Ninja |
- +----+-----------+-------------+
- 4 rows in set (0.00 sec)
二.Inner join
內連線,也叫等值連線,inner join產生同時符合A和B的一組資料。
- mysql> select * from A inner join B on A.name = B.name;
- +----+--------+----+--------+
- | id | name | id | name |
- +----+--------+----+--------+
- | 1 | Pirate | 2 | Pirate |
- | 3 | Ninja | 4 | Ninja |
- +----+--------+----+--------+
三.Left join
- mysql> select * from A left join B on A.name = B.name;
- #或者:select * from A left outer join B on A.name = B.name;
- +----+-----------+------+--------+
- | id | name | id | name |
- +----+-----------+------+--------+
- | 1 | Pirate | 2 | Pirate |
- | 2 | Monkey | NULL | NULL |
- | 3 | Ninja | 4 | Ninja |
- | 4 | Spaghetti | NULL | NULL |
- +----+-----------+------+--------+
- 4 rows in set (0.00 sec)
left join,(或left outer join:在Mysql中兩者等價,推薦使用left join.)左連線從左表(A)產生一套完整的記錄,與匹配的記錄(右表(B)) .如果沒有匹配,右側將包含null。
如果想只從左表(A)中產生一套記錄,但不包含右表(B)的記錄,可以通過設定where語句來執行,如下:
- mysql> select * from A left join B on A.name=B.name where A.id is null or B.id is null;
- +----+-----------+------+------+
- | id | name | id | name |
- +----+-----------+------+------+
- | 2 | Monkey | NULL | NULL |
- | 4 | Spaghetti | NULL | NULL |
- +----+-----------+------+------+
- 2 rows in set (0.00 sec)
同理,還可以模擬inner join. 如下:
- mysql> select * from A left join B on A.name=B.name where A.id is not null and B.id is not null;
- +----+--------+------+--------+
- | id | name | id | name |
- +----+--------+------+--------+
- | 1 | Pirate | 2 | Pirate |
- | 3 | Ninja | 4 | Ninja |
- +----+--------+------+--------+
- 2 rows in set (0.00 sec)
求差集:
根據上面的例子可以求差集,如下:
- SELECT * FROM A LEFT JOIN B ON A.name = B.name
- WHERE B.id IS NULL
- union
- SELECT * FROM A right JOIN B ON A.name = B.name
- WHERE A.id IS NULL;
- # 結果
- +------+-----------+------+-------------+
- | id | name | id | name |
- +------+-----------+------+-------------+
- | 2 | Monkey | NULL | NULL |
- | 4 | Spaghetti | NULL | NULL |
- | NULL | NULL | 1 | Rutabaga |
- | NULL | NULL | 3 | Darth Vader |
- +------+-----------+------+-------------+
四.Right join
- mysql> select * from A right join B on A.name = B.name;
- +------+--------+----+-------------+
- | id | name | id | name |
- +------+--------+----+-------------+
- | NULL | NULL | 1 | Rutabaga |
- | 1 | Pirate | 2 | Pirate |
- | NULL | NULL | 3 | Darth Vader |
- | 3 | Ninja | 4 | Ninja |
- +------+--------+----+-------------+
- 4 rows in set (0.00 sec)
同left join。
Mysql建表思路理解
一對一 one on one
一張表的一條記錄一定只能與另外一張表的一條記錄進行對應,反之亦然。 學生表:姓名,性別,年齡,身高,體重,籍貫,家庭住址,緊急聯絡人 其中姓名、性別、年齡、身高,體重屬於常用資料,但是籍貫、住址和聯絡人為不常用資料 如果每次查詢都是查詢所有資料,不常用的資料就會影響效率,實際又不用 常用資訊表:ID(P),姓名,性別,年齡,身高,體重 不常用資訊表:ID(P),籍貫,家庭住址,緊急聯絡人 解決方案:將常用的和不常用的資訊分享儲存,分成兩張表 不常用資訊表和常用資訊表,保證不常用資訊表與常用資訊表能夠對應上:找一個具有唯一性的 欄位來共同連線兩張表。 一個常用表中的一條記錄永遠只能在一張不常用表中匹配一條記錄,反之亦然。
一對多 one on many
一張表中有一條記錄可以對應另外一張表中的多條記錄;但是反過來,另外一張表的一條記錄 只能對應第一張表的一條記錄,這種關係就是一對多或多對一 母親與孩子的關係:母親,孩子兩個實體 母親表:ID(P),名字,年齡,性別 孩子表:ID(P),名字,年齡,性別 以上關係:一個媽媽可以在孩子表中找到多條記錄(也可能是一條),但是一個孩子只能找到一個媽媽 是一種典型的一對多的關係。 但是以上設計:解決了實體的設計表問題,但是沒有解決關係問題,孩子找不到母親,母親也找不到孩子 解決方案:在某一張表中增加一個欄位,能夠找到另外一張表中的記錄:在孩子表中增加一個欄位 指向母親表,因為孩子表的記錄只能匹配到一條母親表的記錄。 母親表:ID(P),名字,年齡,性別 孩子表:ID(P),名字,年齡,性別,母親表ID(母親表主鍵)
多對多 many on many
一對錶中(A)的一條記錄能夠對應另外一張表(B)中的多條記錄;同時B表中的一條記錄 也能對應A表中的多條記錄 老師和學生 老師表 T_ID(P),姓名,性別 學生表 S_ID(P),姓名,性別 以上設計方案:實現了實體的設計,但是沒有維護實體的關係 一個老師教過多個學生,一個學生也被多個老師教過 解決方案:增加一張中間關係表 老師與學生的關係表:ID(P),T_ID,S_ID 老師表與中間表形成一對多的關係,而中間表是多表;維護了能夠唯一找到一表的關係; 同樣的學生表與中間表也是一個一對多的關係; 學生找老師:找出學生ID--->中間表尋找匹配記錄(多條)--->老師表匹配(一條) 老師找學生:找出老師ID--->中間表尋找匹配記錄(多條)--->學生表匹配(一條)