1. 程式人生 > >[瘋狂Java]SQL-連線查詢:SQL92、SQL99

[瘋狂Java]SQL-連線查詢:SQL92、SQL99

1. 連線查詢:

    1) 即查詢的時候同時需要多張表(特別是存在外來鍵關係的),此時需要多張表之間的值進行連線;

    2) 目前SQL標準提出過兩種連線查詢,第一種是較早的SQL92標準,第二種是目前使用廣泛的較新的SQL99標準;

    3) 92形式簡單,但編寫較為冗長,99不僅在底層得到優化,而且形式看上去更加一目瞭然,邏輯性更強,一般建議使用99標準;

 

2. SQL92:

    1) 多張表需要全部放在from之後,所有的連線條件都放在where當中,因此SQL92中的等值連線、非等值連結、外連線等等其實只是where中的條件不同罷了;

    2) 具體語法:

 

 
  1. select col1, col2, ...

  2. from table1 t1, table2 t2, ...

  3. where ...

!!可以看到需要為表取別名(可以使用as),t1、t2就是各個表的別名,這樣就可以在col1、col2、...以及where子句中使用引用這些別名了;

 

!!區別名的目的:一方面是為了簡化表名(原表名可能很長),其次可能發生自連線的情況(即自己跟自己連線),因此需要為同一張表取兩個不一樣的別名,這樣連線的時候可以“當做”兩張不同的表使用;

    3) 示例:

 
  1. select s.col1, t.col2

  2. from table1 s, table2 t

  3.  
  4. 1. where s.col1 = t.id; // 值相等就是等值連線

  5. 2. where s.col1 > t.id; // 不是相等就是非等值連線

  6. 3. ; // 無where子句就是廣義笛卡爾積

    4) 連線的原理:按照from後面表的出現順序,前面的表作為記憶體的for迴圈,後出現的表作為外層的for迴圈,上面的例子就是這樣實現的

 

 

 
  1. for t in table2

  2. {

  3. for s in talbe1

  4. {

  5. if 滿足where條件 // 廣義笛卡爾積就是去掉if語句直接output

  6. output s + t;

  7. }

  8. }

!!可以看到where子句中以及select後的"表名(或者別名)+'.'+列名"的用法,在這裡表名(別名)其實就代表當前查出來的一條記錄了,而後面跟著的列名就代表該記錄的哪個欄位;

 

    5) 自連線:就是一張表自己跟自己連線,比如員工和經理都在一張表中,現在要將員工的所屬經理的ID和經理的ID連線,此時就要將該表當成兩種表看,一張是普通的員工表,另一張是經理表(只不過經理標中載入這員工,員工表中夾雜著經理,通常需要自連線都表示資料庫設計不合理,非常不提倡);

 

 
  1. select ...

  2. from table s, table t

  3. where ...

!!可以看到只要為同一張表命不同的別名加以區分就行了,可以帶到上面的巢狀for迴圈中檢驗一下;

 

    6) 外連線:各資料庫對SQL92的外連線支援的並不是很好,基本都是在SQL99中全面支援外連線的,這裡MySQL就不支援SQL92的外連線;

 

!!以下內容全部都屬於SQL99:

 

3. SQL99、交叉連線(SQL92的廣義笛卡爾積):

    1) 基本覆蓋了全部型別的連線查詢(包括外連線),並且各大資料庫都能全部支援SQL99的連線查詢;

    2) 直接使用關鍵字:cross join(交叉連線,即廣義笛卡爾積)、natrual join(自然連線)、left join/right join(左右外連線)表示連線型別;

    3) 使用"table xxx join table"的語法來表示哪張表和哪張表進行什麼樣的連線,連線型別一目瞭然,寫法更加符合邏輯,可讀性更好,並且底層支援地更好;

    4) 交叉連線:即SQL92的廣義笛卡爾積,語法如下

 

 
  1. select ...

  2. from 表1

  3. cross join 表2

  4. [corss join 表3...]

!如果有很多表要交叉連線,那麼就繼續cross join下去;

 

    5) 如果select選出的列剛好在各個表中有重名,則需要為表取別名以示區別;

    6) 示例:

 
  1. select s.col1, t.col2

  2. from t1 as s

  3. cross join t2 as t;

!!一般區別名還是建議使用as,如果一下用太多空格可讀性會大大降低!並且as見名知意;


4. 自然連線——通名列組合等值連線:

 

    1) 語法跟交叉連線一模一樣,關鍵字是natural join,格式如下:

 

 
  1. select ...

  2. from 表1

  3. natural join 表2

  4. [natural join 表3...]

    2) 自然連線看上去就是交叉連線,但不過自然連線是有條件,它是等值連線的一種,預設連線的兩張表同名列的組合相等,比如t1和t2進行自然連線,t1有a, b, c三列,t2有b, c, d三列,那麼自然連線時就是找組合t1.(b, c)=t2.(b, c)的記錄連線!記住是同列的組合!!

 

 

5. 指定同名列等值連線:

    1) 前面的自然連線預設會將所有通名列的組合做等值連線,但SQL99也提供了join using語法來指定那些通名列可以做等值連線;

    2) 如果多表之間有通名列,則可以人為指定用哪些通名列做等值連線而不是全部通名列的組合;

    3) 格式:

 

 
  1. select ...

  2. from 表1

  3. join 表2 using(指定通名列或組合)

  4. join 表3 using(指定通名列或組合)

  5. ...

    4) 例如:

 
  1. select *

  2. from t1

  3. join t2 using(col1, col2);

!表示t1和t2以同名列col1、col2的組合做等值連線;

 

    5) SQL99專門為通名列等值連線準備了兩個語法(natural join和join using),可以通名列等值連線在實際中還是非常常用的!

 

6. 自定義等值/不等值連線——對SQL92的擴充套件:

    1) 上面介紹的等值連線都是基於通名列的,那如果想要作為連線條件的列不同名怎麼辦呢?

    2) SQL99提供了join on來達到上述目的,其語法格式:

 

 
  1. select ...

  2. from 表1 別名1

  3. join 表2 別名2 on 表1表2的連線條件

  4. join 表3 別名3 on 表2表3的連線條件

  5. ...

    3) 如果連線條件是相等判斷那就是等值連線,如果是大於、小於等之類的判斷那就是不等值連線了;

 

    4) 例如:等值連線

 

 
  1. select *

  2. from t1

  3. join t2 on t1.col1 = t2.col2;

    5) 例如:不等值連線

 

 

 
  1. select *

  2. from t1

  3. join t2 on t1.col1 > t2.col2;


    6) 可以看到這和SQL92的語法非常相似,只不過92的條件是where子句確定的,而99的條件是由on確定的,但是92顯得更加簡單,為什麼要繼續開發出99呢?

 

 

7. 多表連線的邏輯——為什麼要用SQL99:

    1) 假設3表連線,用92:

 

 
  1. select *

  2. from t1, t2, t3

  3. where t1.col = t3.col and t2.col = t3.col;

!底層的for迴圈其實是由巢狀順序,而該SQL語句非常混亂,首先是巢狀順序各個資料庫實現可能不一樣,MySQL是t1(外)->t2(中)->t3(內),但其它資料庫的巢狀順序可能相反,但如果你明白的知道巢狀順序等細節就可以在寫SQL語句的時候對查詢進行優化;

    2) 而SQL99不存在這個問題,它的join關鍵字其實就是一個顯示的for迴圈!!例如:

 

 
  1. select *

  2. from t1

  3. join t2 on condition1

  4. join t3 on condition2

!就是非常明確的:

 

 

 
  1. for t1 in table1

  2. {

  3. for t2 in table2

  4. {

  5. if condition1

  6. {

  7. for t3 in table3

  8. {

  9. if condition2

  10. output t1 + t2 + t3;

  11. }

  12. }

  13. }

  14. }

    3) 因此在使用SQL99進行多表連線時,連線的順序本身就是底層for迴圈的順序,巢狀結構非常清晰,一目瞭然,就跟直接寫for巢狀一樣,因此99的多表連線顯而易見有如下幾個性質:

 

         i. 連線的物件只能是兩張表,即兩兩連線,傳遞起來就看上去像多張表同時連線,其實就是最近的兩層for迴圈連線在了一起;

         ii. 由for迴圈的作用於可知外層迴圈不能訪問記憶體迴圈的變數(內層對外層不可見),因此SQL99多表連線中上層表的condition中不能訪問下層表,比如在上面的例子中condition1裡不能出現t3,但是下層表可以訪問上層表(for迴圈巢狀中外層的變數對內層來說是可見的),即condition2中可以出現t1和t2!

 

8. 再看自然連線和using連線在超過2張表時的情形:

    1) 先看自然連線:

 

 
  1. select *

  2. from t1

  3. natural join t2

  4. natural join t3

!的言下之意就是:

 

 

 
  1. select *

  2. from t1

  3. join t2 using(t1-t2之間的同名列組)

  4. join t3 using(t2-t3之間的同名列組)

!即條件是相鄰兩列之間的,而並非全部的!!

 

    2) using同樣也符合這個道理,例如:

 

 
  1. select *

  2. from t1

  3. join t2 using(col1)

  4. join t3 using(col1)

!言下之意是:

 

 

 
  1. select *

  2. from t1

  3. join t2 using(t1-t2之間的同名列col1)

  4. join t3 using(t2-t3之間的同名列col1)

!!SQL92的多表連線查詢的連線條件永遠是相鄰兩列之間的!!!

 

 

9. 外連線:

    1) 相比於外連線,之前的連線全部都算內連線,內連線就是隻要符合condition條件的連線都輸出,相反SQL的外連線不僅要把符合condition條件的連線輸出,也要把不符合condition的連線也輸出,但不是完整的輸出!!!

    2) 什麼意思呢?先來看一下左外連線:

         i. table1 左外連線 table2 condition  的言下之意是

 

 
  1. for t1 in table1

  2. {

  3. for t2 in table2

  4. {

  5. if t1-t2滿足condition

  6. output t1 + t2;

  7. }

  8.  
  9. if table2中任意一個t2都不能讓<span style="font-family: Arial, Helvetica, sans-serif;">t1-t2滿足condition</span>

  10. output t1 + null

  11. }

!即滿足條件的連線還是正常地一條一條全部打印出來,但是如果左表(t1)的記錄找不到右表(t2)任意一條記錄能和它滿足條件,那麼就要輸出一條結果,就是不滿足條件的那個座標記錄,但右表的部分全部為null;

         ii. 而右外連線正好相反(巢狀順序也相反):table1 右外連線 table2 condition  的言下之意是

 

 
  1. for t2 in table2

  2. {

  3. for t1 in table1

  4. {

  5. if t1-t2滿足condition

  6. output t1 + t2;

  7. }

  8.  
  9. if table1中任意一個t1都不能讓t1-t2滿足condition

  10. output null + t2;

  11. }

         iii. 全外連線就是左外和右外的結合:table1 全外連線 table2 condition  的言下之意是

 

 
  1. for t1 in table1 // 滿足條件的全部輸出

  2. {

  3. for t2 in table2

  4. {

  5. if t1-t2滿足condition

  6. output t1 + t2;

  7. }

  8. }

  9.  
  10. for t1 in table1 // 輸出左外連線

  11. {

  12. if table2中任意一個t2都不能讓t1-t2滿足condition

  13. output t1 + null;

  14. }

  15.  
  16. for t2 in table2 // 輸出右外連線

  17. {

  18. if table1中的任意一個t1都不能讓t1-t2滿足condition

  19. output null + t2;

  20. }

    3) SQL99的外連線語法:

         i. 關鍵字是left join(左外連線)、right join(右外連線)、full join(全外連線);

         ii. 格式是:

 

 
  1. select ...

  2. from 表1

  3. left/right/full join 表2 on 條件1

  4. left/right/full join 表3 on 條件2

  5. ....