SQL select語句複習
內連線
概念
內連線,也被稱為自然連線,只有兩個表相匹配的行才能在結果集中出現。返回的結果集選取了兩個表中所有相匹配的資料,捨棄了不匹配的資料。可以理解為取兩個表的交集
#
語法
select fieldlist from table1 [inner] join table2 on table1.column = table2.column
舉例
A表 | id | name | | ——— | ——— | | 1 | tom | | 2 | jerry | | 3 | max |
B表 | id | stock | | ——— | ——— | | 1 | 15 | | 2 | 50 |
select * from A inner join B on A.id = B.id
結果 | A.id | name | B.id |stock | | ——— | ——— | ——— | ——— | | 1 | tom | 1 | 15 | 2 | jerry | 2 | 50 |
外連線
概念
外連線不僅包含符合連線條件的行,還包含左表(左連線時)、右表(右連線時)或兩個邊接表(全外連線)中的所有資料行。SQL外連線共有三種類型:左外連線(關鍵字為LEFT OUTER JOIN)、右外連線(關鍵字為RIGHT OUTER JOIN)和全外連線(關鍵字為FULL OUTER JOIN)。外連線的用法和內連線一樣,只是將INNER JOIN關鍵字替換為相應的外連線關鍵字即可。
解釋
- 1.外連線中outer關鍵字是可以省略的
- 2.通俗地講,語句A left (outer) join 連線的記錄數與表A的記錄數相同,A right join B的連線記錄數與B表記錄數相同。A left join B等價於B right join A。
語法
select fieldlist from table1 left/right [outer] join table2 on table1.column = table2.column
舉例
A表 | id | name | | ——— | ——— | | 1 | tom | | 3 | jerry | | 4 | max |
B表 | id | stock | | ——— | ——— | | 1 | 15 | | 2 | 50 | | 4 | 70 |
左連線語句
select * from A left join B on A.id = B.id
結果 | A.id | name | B.id |stock | | ——— | ——— | ——— | ——— | | 1 | tom | 1 | 15 | 3 | jerry | 2 | NULL | | 4| max | 4 | 70| 可以看到,返回的結果集為A表全部記錄,B表中沒有的記錄則返回NULL
右連線語句
select * from B left join A on A.id = B.id
結果 | B.id | stock | A.id |name | | ——— | ——— | ——— | ——— | | 1 | 15 | 1 | tom | 2 | 50 | NULL | NULL | | 4| 70 | 4 | max |
全連線語句
select * form A a full outer join B b on a.id = b.id
結果 | A.id | name | B.id |stock | | ——— | ——— | ——— | ——— | | 1 | tom | 1 | 15 | 3 | jerry | 2 | NULL | | NULL | NULL | 2 | 50 | | 4| max | 4 | 70|
group by
“Group By”從字面意義上理解就是根據“By”指定的規則對資料進行分組,所謂的分組就是將一個“資料集”根據某一欄位劃分成若干個“小區域”,然後針對若干個“小區域”進行資料處理。
舉例
region | population | area | name |
---|---|---|---|
歐洲 | 15 | 2 | 英國 |
歐洲 | 50 | 3 | 法國 |
亞洲 | 70 | 4 | 中國 |
亞洲 | 20 | 3 | 日本 |
查詢每個地區(region)的總人口數和總面積
select region,SUM(population),SUM(area) from table GROUP BY region
採用group by將集合根據地區劃分為幾個不同小集合後,sum()函式再針對每一個小集合進行計算。注意:表中除region(地區)外的欄位,只能通過SUM COUNT等聚合函式運算後返回一個值
Having
Having子句可以讓我們篩選通過Group by成組後的資料:HAVING子句在聚合後對組記錄進行篩選。舉個例子就明白了
舉例
還是上邊那張表,查詢總面積大於6的地區的面積、人口總和
select region,SUM(population),SUM(area) as TotalArea from table GROUP BY region Having TotalArea > 6
練習(來自LeetCode)
查詢Person表中所有重複的電子郵箱 Person | id | Email | | ——— | ——— | | 1 | [email protected] | | 3 | [email protected] | | 4 | [email protected] | 解法1,效率較低
select DISTINCT p1.Email from Person p1,Person p2 where p1.Id != p2.Id and p1.Email = p2.Email
解法2,使用group by having 效率高
select Email from Person Group By Email Having count(Email)>1
in 和 exists
首先,看一道leetCode上的習題 某網站包含兩個表,Customers 表和 Orders 表。編寫一個 SQL 查詢,找出所有從不訂購任何東西的客戶。Customers表有兩個欄位Id和name,Orders表有兩個欄位Id和CustomerId
解法1
select Name as Customers from Customers where not exists (select CustomerId from Orders where Customers.Id = Orders.CustomerId)
解法2
select Name as Customers from Customers where Id not in (select CustomerId from Orders)
以上兩種解法都達到了目的,可是什麼時候用哪種,如何選擇?我們分別看下這兩種語句的原理
in
確定給定的值是否與子查詢或列表中的值相匹配。in在查詢的時候,首先查詢子查詢的表,然後將內表和外表做一個笛卡爾積,然後按照條件進行篩選。所以相對內表比較小的時候,in的速度較快。內表就是子表,即上述例子中括號內查詢的表
笛卡爾積
笛卡爾乘積是指在數學中,兩個集合X和Y的笛卡尓積(Cartesian product),又稱直積,表示為X × Y,第一個物件是X的成員而第二個物件是Y的所有可能有序對的其中一個成員.
例如:假設集合A={a, b},集合B={0, 1, 2},則兩個集合的笛卡爾積為{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
exists
指定一個子查詢,檢測行的存在。首先遍歷迴圈外表,然後看外表中的記錄有沒有和內表的資料一樣的。匹配上就將結果放入結果集中。
使用exits查詢時,首先查詢的是主表,對應上述例子,也就是
select Name as Customers from Customers
然後根據查詢到的每一條記錄,執行後邊的where語句,如果where後的語句成立則返回true,該行結果保留。如果返回的是false,則該行刪除。
比較
我們從exists開始分析,看這樣一條語句
select a.* from A a where exists(select 1 from B b where a.id=b.id)
以上查詢使用了exists語句,exists()會執行A.length次,它並不快取exists()結果集,因為exists()結果集的內容並不重要,重要的是結果集中是否有記錄,如果有則返回true,沒有則返回false. 它的查詢過程類似於以下過程
List resultSet=[];
Array A=(select * from A)
for(int i=0;i<A.length;i++) {
if(exists(A[i].id) {
//執行select 1 from B b where b.id=a.id是否有記錄返回
resultSet.add(A[i]);
}
}
return resultSet;
結論
當B表(可以叫做內表或者子表)資料較大時適合用exists(),如:A表有1千條記錄,B表有十萬條記錄,那麼exists()會執行一千次去判斷A表中的id是否與B表中的id相等. 如:A表有一千條記錄,B表有一百萬條記錄,那麼exists()還是執行一千次,因為它只執行A.length次,可見B表資料越多,越適合exists()發揮效果. 再如:A表有一千條條記錄,B表有一百條記錄,那麼exists()還是執行一千次,還不如使用in()遍歷1000乘以100次,因為in()是在記憶體裡遍歷比較,而exists()需要查詢資料庫,我們都知道查詢資料庫所消耗的效能更高,而記憶體比較很快.
not in和not exists同理