表的加減法
- 表的加法——UNION
首先創(chuàng)建一個(gè)名稱為shop_list2的表便于代碼演示,如下:
+---------+-----------+-----------+------------+-----------+---------------+
| shop_id | shop_name | shop_type | sell_price | buy_price | register_date |
+---------+-----------+-----------+------------+-----------+---------------+
| 0001 | T恤衫 | 衣服 | 1000 | 500 | 2008-09-20 |
| 0002 | 打孔器 | 工具 | 500 | 320 | 2008-09-11 |
| 0003 | 運(yùn)動(dòng)T恤 | 衣服 | 4000 | 2800 | NULL |
| 0009 | 手套 | 衣服 | 800 | 500 | NULL |
| 0010 | 水壺 | 廚房用具 | 2000 | 1700 | 2009-09-20 |
+---------+-----------+-----------+------------+-----------+---------------+
接下來历谍,將兩張表相加:
SELECT shop_id,shop_name
FROM shop_list
UNION
SELECT shop_id,shop_name
FROM shop_list2;
+---------+-----------+
| shop_id | shop_name |
+---------+-----------+
| 0001 | T恤衫 |
| 0002 | 打孔器 |
| 0003 | 運(yùn)動(dòng)T恤 |
| 0004 | 菜刀 |
| 0005 | 砧板 |
| 0006 | 扳手 |
| 0009 | 手套 |
| 0010 | 水壺 |
+---------+-----------+
由表可以看出UNION集合就是并集日川,該集合運(yùn)算符會(huì)除去重復(fù)的記錄。
- 集合運(yùn)算符的注意事項(xiàng)
1.作為運(yùn)算對象的記錄列數(shù)必須相同叮阅;
當(dāng)兩張表的列數(shù)不相同時(shí)刁品,UNION是不能將兩張表相加的。
2.作為運(yùn)算對象的記錄中列的類型必須一致帘饶;
不同類型的數(shù)據(jù)肯定不能存放在同一列的哑诊,如果非要相加的話,可以嘗試類型轉(zhuǎn)換及刻。
3.可以使用任何SELECT 語句镀裤,但ORDER BY子句只能在最后使用一次;
示例:
SELECT shop_id,shop_name
FROM shop_list
WHERE shop_type = '廚房用具'
UNION
SELECT shop_id,shop_name
FROM shop_list2
WHERE shop_type='廚房用具'
ORDER BY shop_id;
+---------+-----------+
| shop_id | shop_name |
+---------+-----------+
| 0004 | 菜刀 |
| 0005 | 砧板 |
| 0010 | 水壺 |
+---------+-----------+
- 包含重復(fù)行的集合運(yùn)算——ALL選項(xiàng)
UNION的結(jié)果沒有包含重復(fù)行缴饭,那么只需要在UNION后面加上ALL關(guān)鍵字的結(jié)果就是可以顯示所有行暑劝,包括重復(fù)行。
SELECT shop_id,shop_name
FROM shop_list
UNION ALL
SELECT shop_id,shop_name
FROM shop_list2;
+---------+-----------+
| shop_id | shop_name |
+---------+-----------+
| 0001 | T恤衫 |
| 0002 | 打孔器 |
| 0003 | 運(yùn)動(dòng)T恤 |
| 0004 | 菜刀 |
| 0005 | 砧板 |
| 0006 | 扳手 |
| 0001 | T恤衫 |
| 0002 | 打孔器 |
| 0003 | 運(yùn)動(dòng)T恤 |
| 0009 | 手套 |
| 0010 | 水壺 |
+---------+-----------+
- 選取表中公共部分——INTERSECT
INTERSECT即為獲取兩個(gè)表的交集颗搂。
SELECT shop_id,shop_name
FROM shop_list
INTERSECT
SELECT shop_id,shop_name
FROM shop_list2
ORDER BY shop_id;
MySQL暫時(shí)不支持INTERSECT用法担猛。
- 表的減法——EXCEPT
EXCEPT即為表1減取與表2中重復(fù)的部分剩下的記錄,用法與UNION相同丢氢。
SELECT shop_id,shop_name
FROM shop_list
EXCEPT
SELECT shop_id,shop_name
FROM shop_list2
ORDER BY shop_id;
Oracle不適用EXCEPT傅联,其擁有特有的MINUS代替EXCEPT,MySQL暫時(shí)不支持EXCEPT這種用法疚察。
聯(lián)結(jié)(以列為單位對表進(jìn)行聯(lián)結(jié))
前面學(xué)習(xí)的集合運(yùn)算都是造成了行的變化蒸走,而聯(lián)結(jié)的作用就是進(jìn)行列的變化。
- 內(nèi)聯(lián)結(jié)——INNER JOIN
演示代碼將會(huì)用到兩張表:
+---------+-----------+-----------+------------+-----------+---------------+
| shop_id | shop_name | shop_type | sell_price | buy_price | register_date |
+---------+-----------+-----------+------------+-----------+---------------+
| 0001 | T恤衫 | 衣服 | 2000 | 500 | 2009-09-20 |
| 0002 | 打孔器 | 工具 | 600 | 100 | 2009-09-20 |
| 0003 | 運(yùn)動(dòng)T恤 | 衣服 | 3000 | 2800 | 2009-09-20 |
| 0004 | 菜刀 | 廚房用具 | 6000 | 2800 | 2009-09-20 |
| 0005 | 砧板 | 廚房用具 | 2000 | 1299 | 2009-09-20 |
| 0006 | 扳手 | 工具 | 3000 | 1500 | 2009-09-20 |
+---------+-----------+-----------+------------+-----------+---------------+
+---------+-----------+---------+--------+
| area_id | area_name | shop_id | number |
+---------+-----------+---------+--------+
| 000A | 北京 | 0001 | 30 |
| 000A | 北京 | 0002 | 50 |
| 000A | 北京 | 0003 | 15 |
| 000B | 上海 | 0002 | 30 |
| 000B | 上海 | 0003 | 120 |
| 000B | 上海 | 0004 | 20 |
| 000B | 上海 | 0006 | 10 |
| 000B | 上海 | 0007 | 40 |
| 000C | 重慶 | 0003 | 20 |
| 000C | 重慶 | 0004 | 50 |
| 000C | 重慶 | 0006 | 90 |
| 000C | 重慶 | 0007 | 70 |
| 000D | 杭州 | 0001 | 100 |
+---------+-----------+---------+--------+
如上表貌嫡,兩張表的列可以分為如下兩類:
1.兩張表中有包含相同的列→shop_id比驻;
2.只存在與一張表內(nèi)的列→除shop_id以外的列该溯;
所謂聯(lián)結(jié),就是"以1中的的列作為橋梁别惦,將2中的滿足其他條件的列匯集到同一結(jié)果中"狈茉。
我們可以試著從shop_list中取出shop_name和sell_price與shop_area中的內(nèi)容進(jìn)行結(jié)合。
SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
FROM shop_area AS SA JOIN shop_list AS SL
ON SA.shop_id=SL.shop_id;
+---------+-----------+---------+-----------+------------+
| area_id | area_name | shop_id | shop_name | sell_price |
+---------+-----------+---------+-----------+------------+
| 000A | 北京 | 0001 | T恤衫 | 2000 |
| 000A | 北京 | 0002 | 打孔器 | 600 |
| 000A | 北京 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000B | 上海 | 0002 | 打孔器 | 600 |
| 000B | 上海 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000B | 上海 | 0004 | 菜刀 | 6000 |
| 000B | 上海 | 0006 | 扳手 | 3000 |
| 000C | 重慶 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000C | 重慶 | 0004 | 菜刀 | 6000 |
| 000C | 重慶 | 0006 | 扳手 | 3000 |
| 000D | 杭州 | 0001 | T恤衫 | 2000 |
+---------+-----------+---------+-----------+------------+
聯(lián)結(jié)需要注意的點(diǎn):
1.FROM子句:因?yàn)槁?lián)結(jié)需要用到兩張或多張表掸掸,使用關(guān)鍵字INNER JOIN就可以把兩張表聯(lián)結(jié)在一起氯庆,雖然使用別名不是必須的,但是過長的表名會(huì)影響可讀性猾漫,所以盡量使用別名点晴。
2.ON子句:ON后面記載的是聯(lián)結(jié)條件,我們可以在ON后面指定聯(lián)結(jié)所使用的列(聯(lián)結(jié)鍵)悯周,ON子句在進(jìn)行聯(lián)結(jié)時(shí)是必不可少的粒督,并且必須書寫在FROM和WHERE之間。
3.SELECT子句:由于使用多張表禽翼,所以列的歸屬會(huì)非惩篱希混亂。所以為了避免混淆列的歸屬闰挡,可以使用<表的別名>.<列名>的方法書寫锐墙。
內(nèi)聯(lián)結(jié)和WHERE子句結(jié)合使用
如果不想了解所有地區(qū)的情況,只想了解上海地區(qū)的情況长酗,可以在聯(lián)結(jié)語句中加入WHERE來限定條件溪北。
SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
FROM shop_area AS SA JOIN shop_list AS SL
ON SA.shop_id=SL.shop_id
WHERE SA.area_id='000B';
+---------+-----------+---------+-----------+------------+
| area_id | area_name | shop_id | shop_name | sell_price |
+---------+-----------+---------+-----------+------------+
| 000B | 上海 | 0002 | 打孔器 | 600 |
| 000B | 上海 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000B | 上海 | 0004 | 菜刀 | 6000 |
| 000B | 上海 | 0006 | 扳手 | 3000 |
+---------+-----------+---------+-----------+------------+
像這樣的聯(lián)結(jié)運(yùn)算結(jié)果,不僅可以使用WHERE子句夺脾,還能使用GROUP BY之拨、HAVING、ORDER BY等咧叭。準(zhǔn)確地說蚀乔,可以完全把它看作一張新的表。
- 外聯(lián)結(jié)——OUTER JOIN
外聯(lián)結(jié)也是通過ON子句使用聯(lián)結(jié)鍵將兩張表進(jìn)行聯(lián)結(jié)菲茬,同時(shí)從兩張表中選出相應(yīng)的列吉挣,基本使用方法沒有改變,但是結(jié)果卻有所不同婉弹。
SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
FROM shop_area AS SA RIGHT OUTER JOIN shop_list AS SL
ON SA.shop_id=SL.shop_id;
+---------+-----------+---------+-----------+------------+
| area_id | area_name | shop_id | shop_name | sell_price |
+---------+-----------+---------+-----------+------------+
| 000A | 北京 | 0001 | T恤衫 | 2000 |
| 000A | 北京 | 0002 | 打孔器 | 600 |
| 000A | 北京 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000B | 上海 | 0002 | 打孔器 | 600 |
| 000B | 上海 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000B | 上海 | 0004 | 菜刀 | 6000 |
| 000B | 上海 | 0006 | 扳手 | 3000 |
| 000C | 重慶 | 0003 | 運(yùn)動(dòng)T恤 | 3000 |
| 000C | 重慶 | 0004 | 菜刀 | 6000 |
| 000C | 重慶 | 0006 | 扳手 | 3000 |
| 000D | 杭州 | 0001 | T恤衫 | 2000 |
| NULL | NULL | NULL | 砧板 | 2000 |
+---------+-----------+---------+-----------+------------+
即使聯(lián)結(jié)鍵在兩張表中沒有都存在睬魂,該行還是會(huì)進(jìn)行聯(lián)結(jié),不存在的數(shù)據(jù)以NULL顯示镀赌。
外聯(lián)結(jié)要點(diǎn):
1.選取出單張表中的全部的信息:只要數(shù)據(jù)存在于某一個(gè)表中汉买,就能夠讀取出來。
2.外聯(lián)結(jié)的主表:外聯(lián)結(jié)中的主表很重要佩脊,哪張為主表蛙粘,那么最總的結(jié)果中會(huì)包含這張主表內(nèi)的所有數(shù)據(jù)。指定主表的關(guān)鍵字是LEFT和RIGTH威彰,使用LEFT時(shí)FROM子句寫在左側(cè)的為主表出牧,反之右側(cè)為主表。
- 3張以上表的聯(lián)結(jié)
原則上歇盼,表的聯(lián)結(jié)對表的數(shù)量沒有限制舔痕。
首先創(chuàng)建一張名稱為storage的表作為第三張需要聯(lián)結(jié)的表:
+------------+---------+----------------+
| storage_id | shop_id | storage_number |
+------------+---------+----------------+
| S001 | 0001 | 0 |
| S001 | 0002 | 120 |
| S001 | 0003 | 200 |
| S001 | 0004 | 3 |
| S001 | 0005 | 0 |
| S001 | 0006 | 99 |
| S001 | 0007 | 999 |
| S001 | 0008 | 200 |
| S002 | 0001 | 10 |
| S002 | 0002 | 25 |
| S002 | 0003 | 34 |
| S002 | 0004 | 19 |
| S002 | 0005 | 99 |
| S002 | 0006 | 0 |
| S002 | 0007 | 0 |
| S002 | 0008 | 18 |
+------------+---------+----------------+
對第三張表進(jìn)行聯(lián)結(jié)
SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price,ST.storage_number
FROM shop_area AS SA INNER JOIN shop_list AS SL
ON SA.shop_id=SL.shop_id
INNER JOIN storage AS ST
ON SA.shop_id=ST.shop_id
WHERE ST.storage_id='S001';
+---------+-----------+---------+-----------+------------+----------------+
| area_id | area_name | shop_id | shop_name | sell_price | storage_number |
+---------+-----------+---------+-----------+------------+----------------+
| 000A | 北京 | 0001 | T恤衫 | 2000 | 0 |
| 000A | 北京 | 0002 | 打孔器 | 600 | 120 |
| 000A | 北京 | 0003 | 運(yùn)動(dòng)T恤 | 3000 | 200 |
| 000B | 上海 | 0002 | 打孔器 | 600 | 120 |
| 000B | 上海 | 0003 | 運(yùn)動(dòng)T恤 | 3000 | 200 |
| 000B | 上海 | 0004 | 菜刀 | 6000 | 3 |
| 000B | 上海 | 0006 | 扳手 | 3000 | 99 |
| 000C | 重慶 | 0003 | 運(yùn)動(dòng)T恤 | 3000 | 200 |
| 000C | 重慶 | 0004 | 菜刀 | 6000 | 3 |
| 000C | 重慶 | 0006 | 扳手 | 3000 | 99 |
| 000D | 杭州 | 0001 | T恤衫 | 2000 | 0 |
+---------+-----------+---------+-----------+------------+----------------+
可以簡單地理解成,將1豹缀,2兩張表先聯(lián)結(jié)伯复,然后將重新生成的表再與表3進(jìn)行聯(lián)結(jié)。
- 交叉聯(lián)結(jié)——CROSS JOIN
SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name
FROM shop_area AS SA CROSS JOIN shop_list AS SL;
+---------+-----------+---------+-----------+
| area_id | area_name | shop_id | shop_name |
+---------+-----------+---------+-----------+
| 000A | 北京 | 0001 | T恤衫 |
| 000A | 北京 | 0001 | 打孔器 |
| 000A | 北京 | 0001 | 運(yùn)動(dòng)T恤 |
| 000A | 北京 | 0001 | 菜刀 |
| 000A | 北京 | 0001 | 砧板 |
| 000A | 北京 | 0001 | 扳手 |
| 000A | 北京 | 0002 | T恤衫 |
| 000A | 北京 | 0002 | 打孔器 |
| 000A | 北京 | 0002 | 運(yùn)動(dòng)T恤 |
| 000A | 北京 | 0002 | 菜刀 |
| 000A | 北京 | 0002 | 砧板 |
| 000A | 北京 | 0002 | 扳手 |
| 000A | 北京 | 0003 | T恤衫 |
| 000A | 北京 | 0003 | 打孔器 |
| 000A | 北京 | 0003 | 運(yùn)動(dòng)T恤 |
| 000A | 北京 | 0003 | 菜刀 |
| 000A | 北京 | 0003 | 砧板 |
| 000A | 北京 | 0003 | 扳手 |
| 000B | 上海 | 0002 | T恤衫 |
| 000B | 上海 | 0002 | 打孔器 |
| 000B | 上海 | 0002 | 運(yùn)動(dòng)T恤 |
| 000B | 上海 | 0002 | 菜刀 |
| 000B | 上海 | 0002 | 砧板 |
| 000B | 上海 | 0002 | 扳手 |
| 000B | 上海 | 0003 | T恤衫 |
| 000B | 上海 | 0003 | 打孔器 |
| 000B | 上海 | 0003 | 運(yùn)動(dòng)T恤 |
| 000B | 上海 | 0003 | 菜刀 |
| 000B | 上海 | 0003 | 砧板 |
| 000B | 上海 | 0003 | 扳手 |
| 000B | 上海 | 0004 | T恤衫 |
| 000B | 上海 | 0004 | 打孔器 |
| 000B | 上海 | 0004 | 運(yùn)動(dòng)T恤 |
| 000B | 上海 | 0004 | 菜刀 |
| 000B | 上海 | 0004 | 砧板 |
| 000B | 上海 | 0004 | 扳手 |
| 000B | 上海 | 0006 | T恤衫 |
| 000B | 上海 | 0006 | 打孔器 |
| 000B | 上海 | 0006 | 運(yùn)動(dòng)T恤 |
| 000B | 上海 | 0006 | 菜刀 |
| 000B | 上海 | 0006 | 砧板 |
| 000B | 上海 | 0006 | 扳手 |
| 000B | 上海 | 0007 | T恤衫 |
| 000B | 上海 | 0007 | 打孔器 |
| 000B | 上海 | 0007 | 運(yùn)動(dòng)T恤 |
| 000B | 上海 | 0007 | 菜刀 |
| 000B | 上海 | 0007 | 砧板 |
| 000B | 上海 | 0007 | 扳手 |
| 000C | 重慶 | 0003 | T恤衫 |
| 000C | 重慶 | 0003 | 打孔器 |
| 000C | 重慶 | 0003 | 運(yùn)動(dòng)T恤 |
| 000C | 重慶 | 0003 | 菜刀 |
| 000C | 重慶 | 0003 | 砧板 |
| 000C | 重慶 | 0003 | 扳手 |
| 000C | 重慶 | 0004 | T恤衫 |
| 000C | 重慶 | 0004 | 打孔器 |
| 000C | 重慶 | 0004 | 運(yùn)動(dòng)T恤 |
| 000C | 重慶 | 0004 | 菜刀 |
| 000C | 重慶 | 0004 | 砧板 |
| 000C | 重慶 | 0004 | 扳手 |
| 000C | 重慶 | 0006 | T恤衫 |
| 000C | 重慶 | 0006 | 打孔器 |
| 000C | 重慶 | 0006 | 運(yùn)動(dòng)T恤 |
| 000C | 重慶 | 0006 | 菜刀 |
| 000C | 重慶 | 0006 | 砧板 |
| 000C | 重慶 | 0006 | 扳手 |
| 000C | 重慶 | 0007 | T恤衫 |
| 000C | 重慶 | 0007 | 打孔器 |
| 000C | 重慶 | 0007 | 運(yùn)動(dòng)T恤 |
| 000C | 重慶 | 0007 | 菜刀 |
| 000C | 重慶 | 0007 | 砧板 |
| 000C | 重慶 | 0007 | 扳手 |
| 000D | 杭州 | 0001 | T恤衫 |
| 000D | 杭州 | 0001 | 打孔器 |
| 000D | 杭州 | 0001 | 運(yùn)動(dòng)T恤 |
| 000D | 杭州 | 0001 | 菜刀 |
| 000D | 杭州 | 0001 | 砧板 |
| 000D | 杭州 | 0001 | 扳手 |
+---------+-----------+---------+-----------+
交叉聯(lián)結(jié)時(shí)邢笙,無法使用ON子句啸如,這是因?yàn)榻徊媛?lián)結(jié)是對兩張表內(nèi)全部記錄進(jìn)行交叉組合,因此結(jié)果中記錄數(shù)通常是兩張表的行數(shù)乘積氮惯。