這一系列講述,兩張表的 Join, 或許你都不一定知道的事兒。
之前寫過 SQL 的編譯原理,很多朋友都不知道 SQL 背后,居然還有編譯一說。SQL 用起來和 C#/JAVA 還是有些異樣的。寫好 SELECT * (雖然這么寫很糟糕?。┮院螅聪?F5 便能得到結果。而不像 C#/Java 需要經過 CLR/JVM 這樣的“轉譯”,才能看到實實在在的程序輸入輸出窗口。
正是由于 SQL 這個隱形編譯器的存在,很多莫名的語法,看起來就很費解。比如最讓初學者頭疼的 Left Join:
本意上,這段 SQL 要達到的目的是,找出 2020 年 1 月 1 日以來,單件商品超過 1000 元銷售額的訂單,并顯示該件商品的產品名。
到底為止,若能根據這個要求,完整寫出上面的 SQL,那就是合格的數據庫開發工程師了。但有些朋友,經常會寫出這樣的 SQL:
還有這樣的 SQL:
看上去,及其相似的三段 SQL,為什么出來的結果就千差萬別呢。甚至,還會把數據庫給跑死。
這就是 SQL 編譯的底層。
要了解 SQL 編譯的底層,要從這張圖,全面入手:
而 Parsing 就是我們正確理解 SQL 執行過程的第一步。
下面這段 SQL 是比較完整的全范本:
細心的讀者可能會留意到每個 SQL 關鍵字前面都有一個用括號包起來的數字,這個數字就是 SQL 關鍵字執行的順序。
我們通常會認為 SELECT 是 SQL 的第一步,其實 FROM 才是,緊接 From 的是 ON, JOIN. 之后才是 WHERE. 正確理解 JOIN 和 WHERE 的執行順序,才可避免 LEFT JOIN 留下的坑。
當然,你別以為這樣就結束了,那我也太不負責任了。接著往下讀。
當兩表 Join 的時候,先按照 ON 的條件做了一次笛卡爾積計算。甭管按照 ON 的條件能不能匹配,匹配的上,就拼接起來;匹配不上的,暫時保留。所以 ON 這一步,兩邊的數據,都會保留在一張虛擬的大表里。
比如,上面兩張表, tblOrderHeader, tblOrderDetail. 他們的外鍵是OrderId.
這兩個表,join 起來,會有這些情況:
tblOrderHeader 有些數據,在 tblOrderDetail 里按照 OrderId 找不到對應的訂單明晰數據。
同樣的,在 tblOrderDetail 中有些明細的訂單,卻在 tblOrderHeader 頭部中找不到訂單表頭信息,比如訂單時間,商店,會員信息等。
更常見的,是互相找不到對應數據
用實線框,框起來的表示兩表可以互相匹配的數據。而對方表缺失的部分就用白色標注。
兩表 Join 的初步結果就出來了,就是上面最后一張圖的情況,即保留兩表所有的數據,匹配上的,排在前頭,匹配不上的依次排在后面。但必須保留兩張表所有的數據。這要牢牢記住。
接著根據第三步 JOIN 的 Join Type(Left join, Right Join, Full Outer Join)來限制留下哪部分。
Left Join, 留下左半部分:
Right Join, 留下右半部分:
Full Outer Join , 左右都留下:
接下來,才是執行 WHERE 命令的時候。
此時,下面這段 SQL , 即
會比這條 SQL , 多出來很多數據:
那是因為,在 WHERE 中,Detail.Amount > 1000 這個命令,限制了右半邊的數據必須要對應上左半邊的OrderId, 所以 tblOrderDetail 中如果沒有 tblOrderHeader 中的OrderId, 則就被舍去。哪怕 tblOrderHeader 的 OrderDate 是符合 OrderDate 大于 2020-01-01的條件。
比如有 tblOrderHeader 是有 5 條記錄,符合 OrderDate 大于 2020-01-01的條件。
我們用紅色實星框表示符合條件的記錄
但最終,因為在 WHERE 中添加了 Detail.Amount > 1000 的條件,相當于把 Left join 改成了 INNER JOIN, 即增加了 Detail.OrderId IS NOT NULL 條件
下面是小編通過一些大廠的朋友要到了他們內部的Java面試題,資料難得,而且還是近一年的真實面試題;
分別有:螞蟻金服、拼多多、阿里云、百度、唯品會、攜程、豐巢科技、樂信、軟通動力、OPPO、銀盛支付、中國平安等初,中級,高級Java面試題集合,附帶超詳細答案,希望能幫助到大家。
還有專門針對JVM、SPringBoot、SpringCloud、數據庫、linux、緩存、消息中間件、源碼等相關面試題。
把Java電子書也分享給大家,大概有10G左右的資源