1. 程式人生 > >SQL select語句複習

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同理