本人曾去某金融軟體公司面試,交流中面試官問的一個問題是:“如果有 A、B 兩張表,A 表中有 2 條數據,B 表中有 200 條數據,請問 SELECT FROM A,B 能查出多少條數據?”。 聽到這個問題的瞬間我就懵了,因為我自己也做過近兩年的面試官,所以我首先會想的就是他問這麼沒有實際意義(實 ...
本人曾去某金融軟體公司面試,交流中面試官問的一個問題是:“如果有 A、B 兩張表,A 表中有 2 條數據,B 表中有 200 條數據,請問 SELECT * FROM A,B 能查出多少條數據?”。
聽到這個問題的瞬間我就懵了,因為我自己也做過近兩年的面試官,所以我首先會想的就是他問這麼沒有實際意義(實際開發中幾乎 100% 的查詢都需要條件)的問題是想考察我什麼呢?同時我心裡也在想,這種逗號的寫法本質上就是內連接,那答案是笛卡爾積嗎?我剛想對面試官說:“我沒這麼寫過,但我分析這種寫法的結果應該是笛卡爾積,也就是 2×200 等於 400……”,正在組織語言的時候被面試官打斷了,他說:“沒關係!我就問問!……”
現在我們來仔細研究下這個問題
首先來創建 t6、t7、t8 共 3 張表,創建語句如下:
CREATE TABLE t6 AS SELECT LEVEL f1,6 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=6;
CREATE TABLE t7 AS SELECT LEVEL f1,7 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=7;
CREATE TABLE t8 AS SELECT LEVEL f1,8 f2,0 f3 FROM DUAL CONNECT BY LEVEL<=8;
然後來看看各個表中的數據分步:
SQL> SELECT t6.* FROM t6;
F1 F2 F3
---------- ---------- ----------
1 6 0
2 6 0
3 6 0
4 6 0
5 6 0
6 6 0
6 rows selected
SQL> SELECT t7.* FROM t7;
F1 F2 F3
---------- ---------- ----------
1 7 0
2 7 0
3 7 0
4 7 0
5 7 0
6 7 0
7 7 0
7 rows selected
SQL> SELECT t8.* FROM t8;
F1 F2 F3
---------- ---------- ----------
1 8 0
2 8 0
3 8 0
4 8 0
5 8 0
6 8 0
7 8 0
8 8 0
8 rows selected
接下來開始我們的實驗:
SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f1=t7.f1; -- res: 6
SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f2=t7.f2; -- res: 0
SELECT COUNT(1) res FROM t6 JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 JOIN t7 ON 1=2; -- res: 0
在 t6 和 t7 兩張表中:f1 欄位值中的 1~6 是相等的,所以結果集行數是 6×1 等於 6;f2 欄位值則完全不想等,所以結果集行數是 6×0 等於 0;f3 欄位值全都相等,所以結果集行數是 6×7 等於 42。
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f1=t7.f1; -- res: 6
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f2=t7.f2; -- res: 6
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 LEFT JOIN t7 ON 1=2; -- res: 6
左連接的時候,會返回左邊表中的所有行,如果左邊表中的行在右邊表中沒有匹配行,則結果集中右邊表中的列返回空值。在這裡,t7.f1 與 t6.f1 有 6 行唯一匹配,所以結果集行數是 6×1 等於 6;t7.f2 與 t6.f2 完全不匹配,所以結果集行數就是 6;t7.f3 中有 7 行能匹配 t6.f3 中的任意行,所以結果集行數是 6×7 等於 42。
接下來回到本文一開始提出的那個問題,先看查詢結果:
SELECT COUNT(1) res FROM t6,t7; -- res: 42
事實上這是一個交叉連接(一定有人會暈倒),交叉連接的標準寫法是:
SELECT COUNT(1) res FROM t6 CROSS JOIN t7; -- res: 42
也許是工作久了的原因,可能大部分人都還記得內連接和外連接(左連接、右連接、全連接),因為內鏈接和左連接還經常用。同時,估計大部分人和我一樣,已經把三大連接中的交叉連接給忘得一干二凈了,原因也很簡單,長時間沒用了!
交叉連接最典型的特點就是沒有 WHERE 子句,交叉連接返回連接表中所有數據行的笛卡爾積,在關係資料庫中的笛卡爾積的結果就是交叉連接所涉及的表中行數之積。
其實 CROSS JOIN 後面也是可以跟 WHERE 子句的,不過那樣它就相當於內連接了。我覺得可以理解為不寫條件就相當於條件恆等,這時的結果集行數就是兩個表中數據行數的乘積,也就是所謂的笛卡爾積。
最後附上同樣從來都用不到的全連接的驗證結果:
SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f1=t7.f1; -- res: 7
SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f2=t7.f2; -- res: 13
SELECT COUNT(1) res FROM t6 FULL JOIN t7 ON t6.f3=t7.f3; -- res: 42
SELECT COUNT(1) res FROM t6 FULL OUTER JOIN t7 ON 1=1; -- res: 42
SELECT COUNT(1) res FROM t6 FULL OUTER JOIN t7 ON 1=2; -- res: 13
最最後附上全連接的定義:完全外部連接返回左邊表和右邊表中的所有行。當某行在一個表中沒有匹配行時,則另一個表中的列將包含空值。如果表之間有匹配行,則整個結果集的行包含基表的數據。
本文鏈接:http://www.cnblogs.com/hanzongze/p/oracle-sql-rows.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!個人博客,能力有限,若有不當之處,敬請批評指正,謝謝!