MySQL開發技巧 第一禪
一、SQL的發展歷程
SQL語言:結構化查詢語言
簡史:從86年開始制定標準 經歷了SQL89 和 SQL92兩個歷程 直到2015
二、SQL語句的分類
常見的SQL語句型別
DDL 資料定義語言 create alt
TPL 事物處理語言
SQL =》 DCL 資料控制語言 grant
DML 資料操作語言
三、join從句----連線
JOIN =》 INNER (內連線
=》 FULL OUTER (全外連線
=》 LEFT OUTER (左外連線
=》 RIGHT OUTER (右外連線
=》 CROSS (交叉連線
示例表結構體及資料
A
1 唐僧
2 豬八戒
3 孫悟空
4 沙僧
B
1 孫悟空
2 牛魔王
3 蛟魔王
4 鵬魔王
5 獅駝王
Join的操作型別—————Inner join
1. 內連線Inner join基於連線謂詞將兩張表的列組合在一起,產生新的結果表,獲取的內容是兩張表的公共的資料
SELECT * FROM a INNER JOIN b ON a.`user_name` = b.`user_name`;
查詢結果:3 孫悟空 1 孫悟空 (可以看出能夠查詢到兩張表公共的部分資料)
Join的操作型別—————Join從句一左外連線—————Left Outer Join
1. SELECT * FROM a left join b on a.user_name = b.user_name
SELECT * FROM a left join b on a.user_name = b.user_name where b.user_name is not null
查詢結果: 1 唐僧
2 豬八戒
3 孫悟空 1 孫悟空
4 沙僧
(A LEFT OUTER JOIN B表示把A表的記錄都顯示出來,把B表符合條件的結果集顯示出來,不符合條件的用NULL表示。)
Join的操作型別——————Join從句一右外連線—————Right Outer Join
1. SELECT * FROM b right join a on b.user_name = a.user_name where a.user_name is not null
查詢結果:
1 唐僧
2 豬八戒
1 孫悟空 3 孫悟空
4 沙僧
(A RIGHT OUTER JOIN B表示把B表的記錄都顯示出來,把A表符合條件的結果集顯示出來,不符合條件的用NULL表示。)
Join的操作型別——————Join從句一全連線—————FULL Join
1. SELECT * FROM a full join b on a.user_name = b.user_name 執行會報錯 大多不支援 需要用集合的方式去查詢
SELECT * FROM a left JOIN b on a.user_name = b.user_name UNION ALL SELECT * FROM b LEFT JOIN a on b.user_name = a.user_name;
查詢結果
1 唐僧
2 豬八戒
3 孫悟空 1 孫悟空
4 沙僧
1 孫悟空 3 孫悟空
2 牛魔王
3 蛟魔王
4 鵬魔王
5 獅駝王
(A FULL OUTER JOIN B 表示把A表和B表的記錄都顯示出來,不符合條件的用NULL表示)
Join的操作型別——————Cross Join—————交叉連線
簡介:交叉連線(Cross Join),又稱笛卡爾積(cartesian join) 或叉乘(Product),如果A和B是兩個集合,他們的交叉連線就記為A * B
1. SELECT * FROM a CROSS JOIN b
查詢結果及特點
1 唐僧 1 孫悟空
2 豬八戒 1 孫悟空
3 孫悟空 1 孫悟空
4 沙僧 1 孫悟空
1 唐僧 2 牛魔王
2 豬八戒 2 牛魔王
3 孫悟空 2 牛魔王
4 沙僧 2 牛魔王
1 唐僧 3 蛟魔王
2 豬八戒 3 蛟魔王
3 孫悟空 3 蛟魔王
4 沙僧 3 蛟魔王
1 唐僧 4 鵬魔王
2 豬八戒 4 鵬魔王
3 孫悟空 4 鵬魔王
4 沙僧 4 鵬魔王
1 唐僧 5 獅駝王
2 豬八戒 5 獅駝王
3 孫悟空 5 獅駝王
4 沙僧 5 獅駝王
(笛卡爾積連線結果)
四、與join相關的開發技巧
如何更新使用過濾條件中包括自身的表?(子查詢 帶條件)
這條SQL的條件是 將都存在與兩張表中的某個欄位進行比較 只有是相同的欄位的資料相同 才進行數值的修改
update a join (select b.`user_name` from a join b on a.user_name = b.user_name) b on a.user_name = b.user_name set a.over='齊天大聖';
解釋 update a join b on a.user_name = b.user_name set a.over='鬥戰聖佛';
五、使用join優化子查詢
寫在前面:子查詢是比較低效的,因為它會將每條記錄都進行匹配(如果資料量大時 會非常的耗時 可以用join進行優化)
join 優化前的SQL語句顯示
select a.user_name,a.over,(select over from b where a.user_name = b.user_name) as over2 from a;
查詢到的資料
+-----------+-----------------+--------+
| user_name | over | over2 |
+-----------+-----------------+--------+
| 唐僧 | 旃檀功德佛 | NULL |
| 豬八戒 | 淨壇使者 | NULL |
| 孫悟空 | 齊天大聖 | 大嬸 |
| 沙僧 | 金身羅漢 | NULL |
+-----------+-----------------+--------+
4 rows in set (0.00 sec)
join 優化後的SQL語句顯示
select a.user_name,a.over,b.over AS over2 from a left join b ON a.user_name = b.user_name;
mysql> select a.user_name,a.over as over3,b.user_name,b.over as over2 from a left join b on a.user_name = b.user_name where b.over is not null;
+-----------+-----------------+--------+
| user_name | over | over2 |
+-----------+-----------------+--------+
| 唐僧 | 旃檀功德佛 | NULL |
| 豬八戒 | 淨壇使者 | NULL |
| 孫悟空 | 齊天大聖 | 大嬸 |
| 沙僧 | 金身羅漢 | NULL |
+-----------+-----------------+--------+
4 rows in set (0.00 sec)
六、使用join優化聚合子查詢
未優化之前的語句
mysql> select a.user_name,c.timestr,c.kills
-> from a join c
-> on a.id = c.user_id
-> where c.kills = (select max(c.kills) from c where a.id = c.user_id);
+-----------+------------+-------+
| user_name | timestr | kills |
+-----------+------------+-------+
| 沙僧 | 2013-01-10 | 3 |
| 孫悟空 | 2013-01-11 | 20 |
| 豬八戒 | 2013-01-07 | 17 |
+-----------+------------+-------+
3 rows in set (0.00 sec)
優化之後的語句
mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id group by a.user_name,c.timestr,c.kills having c.kills = max(c.kills);
+-----------+------------+-------+
| user_name | timestr | kills |
+-----------+------------+-------+
| 沙僧 | 2013-01-10 | 3 |
| 孫悟空 | 2013-01-11 | 20 |
| 豬八戒 | 2013-01-07 | 17 |
+-----------+------------+-------+
------ 以上均顯示 關係中每個最大的值
七、如何實現分組選擇?
什麼是分組選擇?分組選擇就是將資料進行分類 在分類中提取分類中包含的資料
mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id order by c.timestr desc limit 2;
+-----------+------------+-------+
| user_name | timestr | kills |
+-----------+------------+-------+
| 豬八戒 | 2013-01-12 | 10 |
| 豬八戒 | 2013-01-11 | 5 |
+-----------+------------+-------+
mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id where kills = (select max(c.kills) from a where a.id = c.user_id) order by c.kills desc;
+-----------+-------------+-------+
| user_name | timestr | kills |
+-----------+-------------+-------+
| 孫悟空 | 2013-01-11 | 20 |
| 豬八戒 | 2013-01-07 | 17 |
| 豬八戒 | 2013-01-05 | 12 |
| 豬八戒 | 2013-01-10 | 10 |
| 豬八戒 | 2013-01-12 | 10 |
| 豬八戒 | 2013-01-11 | 5 |
| 沙僧 | 2013-01-10 | 3 |
| 豬八戒 | 2013-01-01 | 2 |
| 沙僧 | 2013-01-06 | 1 |
+-----------+-------------+-------+
9 rows in set (0.00 sec)
------ 以上是查詢出 最早日期的兩條殺怪數量
以上查詢的缺陷是
問題: 1. 如果分類或是使用者很多的情況下則需要多次執行同一查詢
2. 增加應用程式同資料庫的互動次數
3. 增加了資料庫執行查詢的次數,不符合批處理的原則
4. 增加了網路流量
優化
mysql> select a.user_name,c.timestr,c.kills from (select c.user_id,c.timestr,c.kills,(select count(*) from c join a where c.user_id = a.id and c.kills <= c.kills) as cnt from c group by c.user_id,c.timestr,c.kills) c join a on a.id = c.user_id order by c.kills desc limit 2;
拆分理解:select a.user_name,c.timestr,c.kills from c join a on a.id = c.user_id;
拆分理解:select c.user_id,c.timestr,c.kills,(select count(*) from c join a where c.user_id = a.id and c.kills <= c.kills) as cnt from c group by c.user_id,c.timestr,c.kills
+-----------+------------+-------+
| user_name | timestr | kills |
+-----------+------------+-------+
| 孫悟空 | 2013-01-11 | 20 |
| 豬八戒 | 2013-01-07 | 17 |
+-----------+------------+-------+
2 rows in set (0.01 sec)