mysql數(shù)據(jù)庫
知識要點:
單表查詢
子查詢
聯(lián)表查詢
事務(wù)
在進行查詢之前,我們要先建好關(guān)系表,并往數(shù)據(jù)表中插入些數(shù)據(jù)。為查詢操作做好準備。
五張關(guān)系表的創(chuàng)建:
#創(chuàng)建并進入數(shù)據(jù)庫:
mysql>CREATEDATABASE`info`;
QueryOK,1rowaffected (0.00sec)
mysql>USE`info`;
Databasechanged
?
#創(chuàng)建學院表:
mysql>CREATETABLE`department`(
->`id`INTPRIMARYKEYAUTO_INCREMENT,
->`name`VARCHAR(20)NOTNULL
?? -> );
QueryOK,0rows affected (0.69sec)
#創(chuàng)建學生表:
mysql>CREATETABLE`students`(
->`s_id`INTPRIMARYKEYAUTO_INCREMENT,
->`name`VARCHAR(20)NOTNULL,
->`d_id`INT,
->FOREIGNKEY(`d_id`)REFERENCES`department`(`id`)
?? -> );
QueryOK,0rows affected (0.65sec)
#創(chuàng)建學生的詳細信息表:
mysql>CREATETABLE`stu_details`(
->`s_id`INTPRIMARYKEY,
->`age`INT,
->`gender`CHAR(1)
?? -> ,
->FOREIGNKEY(`s_id`)REFERENCES`students`(`s_id`)
?? -> );
QueryOK,0rows affected (0.55sec)
#創(chuàng)建課程表:
mysql>CREATETABLE`course`(
->`id`INTPRIMARYKEYAUTO_INCREMENT,
->`name`VARCHAR(20)NOTNULL
?? -> );
QueryOK,0rows affected (0.50sec)
#創(chuàng)建中間表:
mysql>CREATETABLE`select`(
->`s_id`INT,
->`c_id`INT,
->PRIMARYKEY(`s_id`,`c_id`),
->FOREIGNKEY(`s_id`)REFERENCES`students`(`s_id`),
->FOREIGNKEY(`c_id`)REFERENCES`course`(`id`)
?? -> );
QueryOK,0rows affected (0.84sec)
#查看當前存在的表:
mysql>SHOWTABLES;
+----------------+
| Tables_in_info |
+----------------+
| course ? ? ? ? |
| department ? ? |
|select|
| stu_details ?? |
| students ? ? ? |
+----------------+
5rowsinset(0.00sec)
往數(shù)據(jù)表中添加數(shù)據(jù)
#往學院表中添加數(shù)據(jù):
mysql>INSERTINTO`department`(`name`)
->VALUES('外國語'),
-> ? ? ? ('藝術(shù)'),
-> ? ? ? ('計算機'),
-> ? ? ? ('化工')
?? -> ;
QueryOK,4rows affected (0.11sec)
Records:4Duplicates:0Warnings:0
#往學生表中添加數(shù)據(jù):
mysql>INSERTINTO`students`(`name`,`d_id`)
->VALUES('小明',1),
-> ? ? ? ('小紅',3),
-> ? ? ? ('小花',3),
-> ? ? ? ('小新',4)
?? -> ;
QueryOK,4rows affected (0.09sec)
Records:4Duplicates:0Warnings:0
#往學生詳細信息表中添加數(shù)據(jù):
mysql>INSERTINTOstu_details
->VALUES(1,18,'m'),
-> ? ? ? (4,20,'m'),
-> ? ? ? (3,16,'f'),
-> ? ? ? (2,19,'f')
?? -> ;
QueryOK,4rows affected (0.11sec)
Records:4Duplicates:0Warnings:0
#往課程表中添加數(shù)據(jù):
mysql>INSERTINTO`course`
-> (`name`)VALUES
-> ('心理學'),
-> ('佛學'),
-> ('近代史'),
-> ('音樂鑒賞')
?? -> ;
QueryOK,4rows affected (0.08sec)
Records:4Duplicates:0Warnings:0
#查看中間表的結(jié)構(gòu):
mysql>DESC`select`;
+-------+---------+------+-----+---------+-------+
|Field| Type ?? |Null|Key|Default| Extra |
+-------+---------+------+-----+---------+-------+
| s_id? |int(11) |NO| PRI |NULL| ? ? ? |
| c_id? |int(11) |NO| PRI |NULL| ? ? ? |
+-------+---------+------+-----+---------+-------+
2rowsinset(0.03sec)
#往中間表中添加數(shù)據(jù)
mysql>INSERTINTO`select`
->VALUES(1,2),
-> ? ? ? (1,4),
-> ? ? ? (2,1),
-> ? ? ? (2,4),
-> ? ? ? (4,1),
-> ? ? ? (4,2),
-> ? ? ? (4,4)
?? -> ;
QueryOK,7rows affected (0.06sec)
Records:7Duplicates:0Warnings:0
查詢
查詢所有記錄
SELECT * FROM? tb_name;
查詢選中列記錄
SELECT col_name1,col_name2 FROM tb_name;
查詢指定條件下的記錄
SELECT col_name FROM? tb_name? WHERE 條件
查詢后為列取別名
SELECT? col_name? AS? new_name? FROM? tab_name
#查詢所有記錄:
mysql>SELECT*FROM`students`;
+------+--------+------+
| s_id | name ? | d_id |
+------+--------+------+
|1| 小明 ? |1|
|2| 小紅 ? |3|
|3| 小花 ? |3|
|4| 小新 ? |4|
+------+--------+------+
4rowsinset(0.00sec)
?
#查詢選中列記錄
mysql>SELECTname,d_idFROMstudents;
+--------+------+
| name ? | d_id |
+--------+------+
| 小明 ? |1|
| 小紅 ? |3|
| 小花 ? |3|
| 小新 ? |4|
+--------+------+
4rowsinset(0.00sec)
?
#查詢指定條件下的記錄
mysql>SELECT*FROMstudentsWHERE`name`='小紅';
+------+--------+------+
| s_id | name ? | d_id |
+------+--------+------+
|2| 小紅 ? |3|
+------+--------+------+
1rowinset(0.00sec)
?
#查詢后為列取別名
mysql>SELECTnameAS`姓名`,d_idAS學院idFROMstudentsWHEREs_id>=2;
+--------+----------+
| 姓名 ? | 學院id ? |
+--------+----------+
| 小紅 ? |3|
| 小花 ? |3|
| 小新 ? |4|
+--------+----------+
3rowsinset(0.00sec)
排序ORDER BY
ASC升序(默認)? DESC降序
#查詢學生的選修表(中間表)
mysql>SELECT*FROM`select`;
+------+------+
| s_id | c_id |
+------+------+
|2|1|
|4|1|
|1|2|
|4|2|
|1|4|
|2|4|
|4|4|
+------+------+
7rowsinset(0.00sec)
?
#按學生學號升序輸出
mysql>SELECT*FROM`select`ORDERBY`s_id`;
+------+------+
| s_id | c_id |
+------+------+
|1|2|
|1|4|
|2|1|
|2|4|
|4|1|
|4|2|
|4|4|
+------+------+
7rowsinset(0.00sec)
?
#按課程id降序輸出:
mysql>SELECT*FROM`select`ORDERBY`c_id`DESC;
+------+------+
| s_id | c_id |
+------+------+
|4|4|
|2|4|
|1|4|
|4|2|
|1|2|
|4|1|
|2|1|
+------+------+
7rowsinset(0.00sec)
限制顯示數(shù)據(jù)的數(shù)量LIMIT
#按學生學號升序輸出的前4條數(shù)據(jù)
mysql>SELECT*FROM`select`ORDERBY`s_id`LIMIT4;
+------+------+
| s_id | c_id |
+------+------+
|1|2|
|1|4|
|2|1|
|2|4|
+------+------+
4rowsinset(0.00sec)
#指定的返回的數(shù)據(jù)的位置和數(shù)量
mysql>SELECT*FROM`select`ORDERBY`s_id`LIMIT4,2;
+------+------+
| s_id | c_id |
+------+------+
|4|1|
|4|2|
+------+------+
2rowsinset(0.00sec)
分組查詢GROUP BY
例:
對學生表中學院欄進行分組,并統(tǒng)計學院的學生人數(shù):
mysql> SELECT d_id AS 學院id,count(d_id) AS 學生個數(shù) FROM students GROUP BY `d_id`;
+----------+--------------+
| 學院id ? | 學生個數(shù) ? ? |
+----------+--------------+
| ? ? ?? 1 | ? ? ? ? ?? 1 |
| ? ? ?? 3 | ? ? ? ? ?? 2 |
| ? ? ?? 4 | ? ? ? ? ?? 1 |
+----------+--------------+
3 rows in set (0.00 sec)
?
HAVING分組條件
HAVING 后的字段必須是SELECT后出現(xiàn)過的
mysql> SELECT d_id AS 學院id,count(d_id) AS 學生個數(shù) FROM students GROUP BY `d_id`HAVING? 學生個數(shù)=1;
+----------+--------------+
| 學院id ? | 學生個數(shù) ? ? |
+----------+--------------+
| ? ? ?? 1 | ? ? ? ? ?? 1 |
| ? ? ?? 4 | ? ? ? ? ?? 1 |
+----------+--------------+
2 rows in set (0.01 sec)
查詢中一些較為常見的函數(shù)
#求最大年齡
mysql>SELECTMAX(`age`)FROM`stu_details`;
+------------+
|MAX(`age`) |
+------------+
|20|
+------------+
1rowinset(0.03sec)
#求最小年齡
mysql>SELECTMIN(`age`)FROM`stu_details`;
+------------+
|MIN(`age`) |
+------------+
|16|
+------------+
1rowinset(0.00sec)
#求和
mysql>SELECTSUM(`age`)FROM`stu_details`;
+------------+
|SUM(`age`) |
+------------+
|73|
+------------+
1rowinset(0.05sec)
#求平均數(shù)
mysql>SELECTAVG(`age`)FROM`stu_details`;
+------------+
|AVG(`age`) |
+------------+
|18.2500|
+------------+
1rowinset(0.00sec)
子查詢
出現(xiàn)在其他SQL語句內(nèi)的SELECT字句。
1)嵌套在查詢內(nèi)部2)必須始終出現(xiàn)在圓括號內(nèi)3)可以包含多個關(guān)鍵字或條件
#查找出大于平均年齡的數(shù)據(jù)
mysql>SELECT*FROM`stu_details`WHERE`age`>18.25;
+------+------+--------+
| s_id | age? | gender |
+------+------+--------+
|2|19| f ? ?? |
|4|20| m ? ?? |
+------+------+--------+
2rowsinset(0.00sec)
#將平均數(shù)的SQL語句作為子查詢放入上一條語句中
mysql>SELECT*FROM`stu_details`WHERE`age`>(SELECTAVG(`age`)FROM`stu_details`);
+------+------+--------+
| s_id | age? | gender |
+------+------+--------+
|2|19| f ? ?? |
|4|20| m ? ?? |
+------+------+--------+
2rowsinset(0.10sec)
聯(lián)表查詢
內(nèi)連接[INNER| CROSS] JOIN
無條件內(nèi)連接:無條件內(nèi)連接,又名交叉連接/笛卡爾連接第一張表種的每一向會和另一張表的每一項依次組合
有條件內(nèi)連接在無條件的內(nèi)連接基礎(chǔ)上,加上一個ON子句當連接的時候,篩選出那些有實際意義的記錄行來進行拼接
在寫條件時注意兩張表的列名是否一樣,如果時一樣的則要在前面加上表名,tb_name.colname這種形式存在
#無條件內(nèi)連接:
mysql>SELECT*FROM`students`INNERJOIN`department`;
+------+--------+------+----+-----------+
| s_id | name ? | d_id | id | name ? ?? |
+------+--------+------+----+-----------+
|1| 小明 ? |1|1| 外國語 ?? |
|2| 小紅 ? |3|1| 外國語 ?? |
|3| 小花 ? |3|1| 外國語 ?? |
|4| 小新 ? |4|1| 外國語 ?? |
|1| 小明 ? |1|2| 藝術(shù) ? ?? |
|2| 小紅 ? |3|2| 藝術(shù) ? ?? |
|3| 小花 ? |3|2| 藝術(shù) ? ?? |
|4| 小新 ? |4|2| 藝術(shù) ? ?? |
|1| 小明 ? |1|3| 計算機 ?? |
|2| 小紅 ? |3|3| 計算機 ?? |
|3| 小花 ? |3|3| 計算機 ?? |
|4| 小新 ? |4|3| 計算機 ?? |
|1| 小明 ? |1|4| 化工 ? ?? |
|2| 小紅 ? |3|4| 化工 ? ?? |
|3| 小花 ? |3|4| 化工 ? ?? |
|4| 小新 ? |4|4| 化工 ? ?? |
+------+--------+------+----+-----------+
16rowsinset(0.04sec)
#有條件內(nèi)連接:
mysql>SELECT*FROM`students`INNERJOIN`department`
->ONd_id=id;
+------+--------+------+----+-----------+
| s_id | name ? | d_id | id | name ? ?? |
+------+--------+------+----+-----------+
|1| 小明 ? |1|1| 外國語 ?? |
|2| 小紅 ? |3|3| 計算機 ?? |
|3| 小花 ? |3|3| 計算機 ?? |
|4| 小新 ? |4|4| 化工 ? ?? |
+------+--------+------+----+-----------+
4rowsinset(0.03sec)
有條件的外連接:{ LEFT| RIGHT } [OUTER] JOIN
左外連接:兩張表做連接的時候,在連接條件不匹配的時候留下左表中的數(shù)據(jù),而右表中的數(shù)據(jù)以NULL填充
右外連接對兩張表做連接的時候,在連接條件不匹配的時候留下右表中的數(shù)據(jù),而左表中的數(shù)據(jù)以NULL填充
#往學生表中添加數(shù)據(jù),只添加名字
mysql>INSERTINTOstudents(name)
->VALUES('xixi');
QueryOK,1rowaffected (0.11sec)
#查看所有學生表數(shù)據(jù)
mysql>SELECT*FROMstudentS;
+------+--------+------+
| s_id | name ? | d_id |
+------+--------+------+
|1| 小明 ? |1|
|2| 小紅 ? |3|
|3| 小花 ? |3|
|4| 小新 ? |4|
|5| xixi ? |NULL|
+------+--------+------+
5rowsinset(0.00sec)
#使用內(nèi)連接加條件只能看到有分配好學院的學生的信息;
mysql>SELECT*FROMstudentsINNERJOINdepartment
->ONd_id=id;
+------+--------+------+----+-----------+
| s_id | name ? | d_id | id | name ? ?? |
+------+--------+------+----+-----------+
|1| 小明 ? |1|1| 外國語 ?? |
|2| 小紅 ? |3|3| 計算機 ?? |
|3| 小花 ? |3|3| 計算機 ?? |
|4| 小新 ? |4|4| 化工 ? ?? |
+------+--------+------+----+-----------+
4rowsinset(0.02sec)
#使用左連接把學生的數(shù)據(jù)全取出來,該學生沒有學院信息的用NULL填充
mysql>SELECT*FROMstudentsLEFTJOINdepartment
->ONd_id=id;
+------+--------+------+------+-----------+
| s_id | name ? | d_id | id ? | name ? ?? |
+------+--------+------+------+-----------+
|1| 小明 ? |1|1| 外國語 ?? |
|2| 小紅 ? |3|3| 計算機 ?? |
|3| 小花 ? |3|3| 計算機 ?? |
|4| 小新 ? |4|4| 化工 ? ?? |
|5| xixi ? |NULL|NULL|NULL|
+------+--------+------+------+-----------+
5rowsinset(0.00sec)
#使用右外連接把目前還沒有學生的學院的數(shù)據(jù)也顯示出來
mysql>SELECT*FROMstudentsRIGHTJOINdepartment
->ONd_id=id;
+------+--------+------+----+-----------+
| s_id | name ? | d_id | id | name ? ?? |
+------+--------+------+----+-----------+
|1| 小明 ? |1|1| 外國語 ? ? |
|2| 小紅 ? |3|3| 計算機 ? ? |
|3| 小花 ? |3|3| 計算機 ? ? |
|4| 小新 ? |4|4| 化工 ? ? ? |
|NULL|NULL|NULL|2| 藝術(shù) ? ?? |
+------+--------+------+----+-----------+
5rowsinset(0.00sec)
?
mysql>
查詢SQL的優(yōu)化
MySQL的執(zhí)行順序
1.FROM: 對FROM的左邊的表和右邊的表計算笛卡爾積。產(chǎn)生虛表VT1
?
2.ON: 對虛表VT1進行ON篩選,只有那些符合的行才會被記錄在虛表VT2中。
?
3.JOIN: 如果指定了OUTERJOIN(比如leftjoin、rightjoin),那么保留表中未匹配的行就會作為外部行添加到虛擬表VT2中,產(chǎn)生虛擬表VT3, rugfrom子句中包含兩個以上的表的話,那么就會對上一個join連接產(chǎn)生的結(jié)果VT3和下一個表重復(fù)執(zhí)行步驟1~3這三個步驟,一直到處理完所有的表為止。
?
4.WHERE: 對虛擬表VT3進行WHERE條件過濾。只有符合的記錄才會被插入到虛擬表VT4中。
?
5.GROUPBY: 根據(jù)groupby子句中的列,對VT4中的記錄進行分組操作,產(chǎn)生VT5.
?
6.CUBE |ROLLUP: 對表VT5進行cube或者rollup操作,產(chǎn)生表VT6.
?
7.HAVING: 對虛擬表VT6應(yīng)用having過濾,只有符合的記錄才會被 插入到虛擬表VT7中。
?
8.SELECT: 執(zhí)行select操作,選擇指定的列,插入到虛擬表VT8中。
?
9.DISTINCT: 對VT8中的記錄進行去重。產(chǎn)生虛擬表VT9.
?
10.ORDERBY: 將虛擬表VT9中的記錄按照進行排序操作,產(chǎn)生虛擬表VT10.
?
11.LIMIT:取出指定行的記錄,產(chǎn)生虛擬表VT11, 并將結(jié)果返回。
通過上面的執(zhí)行順序不難想到,要想SQL執(zhí)行更快,就必須把篩選條件盡量的往前面放。如下:
SELECT
? ? s.`name`,
? ? e.`name`
FROM
? ? `students`s
LEFTJOIN(
? ? ? ? SELECT
? ? ? ? ? ? se.`s_id`,
? ? ? ? ? ? c.`name`
? ? ? ? FROM
? ? ? ? ? ? `select`se
? ? ? ? JOIN`course`cONse.`c_id`= c.`id`
? ? ) eONs.`id`=e.`stu_id`
?
?
SELECT
? ? *
FROM
? ? `student`s
WHERE
? ? s.`dep_id`= (
? ? ? ? SELECT
? ? ? ? ? ? `id`
? ? ? ? FROM
? ? ? ? ? ? `department`d
? ? ? ? WHERE
? ? ? ? ? ? d.`name`='外國語學院'
? ? )
在這兩個例子中,第一個SQL中的子表只會被查詢一次,但是在第二個SQL中,子表會被執(zhí)行n次,這個n取決student表中的數(shù)據(jù)條數(shù),如果子表的數(shù)據(jù)量很大的話,那么SQL的執(zhí)行速度會十分慢。
這是典型的通過執(zhí)行順序來優(yōu)化SQL,除此之外,要想SQL執(zhí)行快一點,應(yīng)該盡量避免模糊匹配,如:like,in,not in 等這些匹配條件。
還有幾點建議給大家:
1.盡量避免整表掃描,如SELECT *
2.建立合適的索引
3.使用合適的存儲引擎
4.在JOIN中,盡量用小表LEFT JOIN 大表
5.除非十分必要,盡量不要使用ORDER BY,GROUP BY 和 DISTINCT(去重),盡量用索引來代替
事務(wù)
為了保證數(shù)據(jù)庫記錄的更新從一個一致性狀態(tài)變更為另一個一致性狀態(tài)使用事務(wù)來處理是非常必要。
例:
創(chuàng)建一張銀行賬戶的表
mysql> CREATE TABLE `account`(
? ? -> `id` INT PRIMARY KEY AUTO_INCREMENT,
? ? -> `name` VARCHAR(20) NOT NULL,
? ? -> `balance` INT
? ? -> );
Query OK, 0 rows affected (0.52 sec)
添加兩個用戶及用戶的存款的信息
mysql> INSERT INTO `account`(`name`,`balance`)
? ? ->? VALUES('shangdian',10000),
? ? ->? ? ? ? ('xiaoming',2000)
? ? -> ;
Query OK, 2 rows affected (0.09 sec)
Records: 2? Duplicates: 0? Warnings: 0
假設(shè)現(xiàn)在用戶小明在商店買了500元東西,現(xiàn)在要轉(zhuǎn)賬給商店,那么就需要從小明的賬戶上減去500,然后在商店的用戶上加上500,但是如果在減500的過程中出現(xiàn)了系統(tǒng)故障,再重新啟動后發(fā)現(xiàn)小明的錢扣了,但商店卻沒有收到,這時候就會出現(xiàn)數(shù)據(jù)變動不一致。對于這種數(shù)據(jù)的修改我們需要的就是要么同時修改成功,要么同時修改失敗,所以這就需要用事務(wù)來進行出來。
START TRANSACTION:開始一個新的事務(wù)
COMMIT:提交當前事務(wù),做出永久改變
ROLLBACK:回滾當前事務(wù),放棄修改
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE `account`
? ? -> SET `balance`= `balance`-50
? ? -> WHERE `name` ='xiaoming'
? ? -> ;
Query OK, 1 row affected (0.04 sec)
Rows matched: 1? Changed: 1? Warnings: 0
使用ROLLBACK;使數(shù)據(jù)的修改不生效,回到事務(wù)前的狀態(tài):
mysql> ROLLBACK;
Query OK, 0 rows affected (0.06 sec)
做一次正確的操作:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE `account`
? ? -> SET `balance`=`balance`-50
? ? -> WHERE `name`='xiaoming'
? ? -> ;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1? Changed: 1? Warnings: 0
mysql> UPDATE `account`
? ? -> SET `balance`=`balance`+50
? ? ->
? ? -> WHERE `name`='shangdian'
? ? -> ;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1? Changed: 1? Warnings: 0
mysql> SELECT * FROM `account`;
mysql> COMMIT;
Query OK, 0 rows affected (0.07 sec)
當COMMIT后,數(shù)據(jù)修改成功,ROLLBACK也沒法回到之前了。
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)