文章目錄
表的別名(AS關鍵字)
之前只用as給計算字段起過別名,由於有時候不區分計算字段和列,所以也可以說as可以用於給列起別名。總之,as可以給列和計算字段起別名,還可以給表起別名。
select concat(vend_name, '(', vend_country, ')')
as vend_title
from vendors
order by vend_name;
計算字段必須用as起別名,因爲不起名字就是匿名的,沒法用。
但是給表起別名則是真的別名,可選的,不起人家也有名字。
select cust_name, cust_contact
from customers as C, orders as O, orderItems as OI
where prod_id = 'RGAN01'
AND OI.order_num = O.order_num
and C.cust_id = O.cust_id;
爲什麼給表起別名
一直覺得這種起別名的方式很類似C和C++的typedef關鍵字,所以作用當然也有類似的點:縮短代碼。
很難理解,用一個例子來說明:
示例:在一條select語句多次引用一個表
太牛了
假設,我們要給和Jim Jones同一公司的所有顧客發郵件,那麼就要找出和Jim Jones同公司的所有顧客,假設我們只找名字,郵箱先不說。
那麼首先應該根據Jim Jones來找到Jim Jones工作的公司,然後再去找所有在這個公司工作的顧客。
使用子查詢
最內層的查詢:找到Jim Jones工作的公司
select cust_name
from Customers
where cust_contact = "Jim Jones";
結果是fun4all公司。
然後直接加上外層查詢,寫成嵌套的樣子:
select cust_id, cust_name, cust_contact
from Customers
where cust_name in (select cust_name
from Customers
where cust_contact = "Jim Jones");
於是就找到了Dennise這個顧客。
使用自聯結搭配表別名
select c1.cust_id, c1.cust_name, c1.cust_contact
from Customers as c1, Customers as c2 -- 牛不牛逼
where c2.cust_contact = "Jim Jones"
and c1.cust_name = c2.cust_name;
注意別名雖然在第二行才定義,但是第一行就在用了,因爲這是一個語句,分行只是格式而已。
第一個聯結條件用於過濾出c2表中所有聯繫人爲Jim Jones的行,其實就一行,即公司名cust_name爲fun4all的那行;
第二個條件再過濾出c1表中所有和c2表中過濾出的行的公司名相同的行,於是就得到這兩行結果。
注意最後顯示的是c1表的過濾結果,這個是重要的,因爲c2被過濾的只剩一行了
如果把第一行代碼改爲c2
select c2.cust_id, c2.cust_name, c2.cust_contact
from Customers as c1, Customers as c2 -- 牛不牛逼
where c2.cust_contact = "Jim Jones"
and c1.cust_name = c2.cust_name;
則顯示兩次jim的信息,因爲c2被過濾的只剩一行,卻又和c1匹配了2次
- 很多DBMS處理聯結的速度比子查詢快得多。所以還是儘量用聯結。雖然不懂爲什麼會快得多,大概是底層代碼原因。
- 用表別名引用的兩個表雖然是同一個表,但是DBMS卻把他們完全當做兩個表,這樣真的很方便。
和列別名的區別:不返回到客戶端;只在查詢時使用
其他聯結(除內聯結外)
自聯結 self join
見上一節的 示例:在一條select語句多次引用一個表
自然聯結 natural join:可能永遠也不會用到不是自然聯結的內聯結
由於沒出現過不是自然聯結的內聯結,所以並不清楚相同列多次出現是啥樣的
select C.*, O.order_num, O.order_date,
OI.prod_id, OI.quantity, OI.item_price
from Customers as C, Orders as O, OrderItems as OI
WHERE C.cust_id = O.cust_id
and OI.order_num = O.order_num
and prod_id = 'RGAN01';
可以看到select後面都是完全限定列名
外聯結 outer join
大概明白意思,因爲如果一個顧客沒有下訂單,他這行就不會關聯到orders表的某一行,於是聯結時就過濾不出來他這一行。
示例:左外聯結和右外聯結
假設要檢索出所有顧客,以及他們的訂單編號,使用內聯結寫代碼:
select Customers.cust_id, Orders.order_num
from Customers inner join Orders
on Customers.cust_id = Orders.cust_id;
- 用了完全限定列名指明返回數據來自哪個表
- inner join是用在from子句中的,把顧客表和訂單表聯結起來了
- 聯結的條件用on子句寫
如果用外聯結寫:
select Customers.cust_id, Orders.order_num
from Customers left outer join Orders
on Customers.cust_id = Orders.cust_id;
- left outer join,則要選擇顧客表的所有行,即沒在orders表的不滿足聯結條件的行也過濾出來。2號顧客沒下訂單,也被檢索出來了。
- 如果用right,則訂單表的所有行都有,但是有訂單編號就一定有顧客編號,因爲下單了就已經是顧客了,所以這樣得到的結果和內聯結一樣。
select Customers.cust_id, Orders.order_num
from Customers right outer join Orders
on Customers.cust_id = Orders.cust_id;
- 左外聯結和右外聯結可以互換,只要把表的順序換一下就好了
select Customers.cust_id, Orders.order_num
from Orders right outer join Customers
on Customers.cust_id = Orders.cust_id;
全外聯結(mysql不支持)
相當於左外聯結和右外聯結的結合版本了
select Customers.cust_id, Orders.order_num
from Orders full outer join Customers
on orders.cust_id = Customers.cust_id;
代碼報錯,因爲mysql不支持
帶聚集函數的聯結
之前學了5個聚集函數,count是其中之一
要和group by 一起用
內聯結
select Customers.cust_id,
count(Orders.order_num) as num_order
from Customers inner join Orders
on Customers.cust_id = Orders.cust_id
group by Customers.cust_id;
外左聯結
select Customers.cust_id,
count(Orders.order_num) as num_order
from Customers left outer join Orders
on Customers.cust_id = Orders.cust_id
group by Customers.cust_id;
使用聯結的注意要點
用聯結條件:
select cust_name, cust_contact
from customers as C, orders as O, orderItems as OI
where prod_id = 'RGAN01'
AND OI.order_num = O.order_num
and C.cust_id = O.cust_id;
不用聯結條件,返回笛卡爾積:
select cust_name, cust_contact
from customers as C, orders as O, orderItems as OI;
下圖不完整,但是能明白意思