如何成為寫SQL高手(下)

四、SQL基礎(chǔ)理論知識

? ? 掌握基礎(chǔ)理論知識是成為SQL高手第一步,我不會照搬教科書式的講課,我只會講解我認為你最應(yīng)該的掌握的3個知識點。

? 1、集合(Set)。我給大家一個簡單的概念,sql里面一切皆集合。SQL 以關(guān)系代數(shù)為基礎(chǔ)發(fā)展出來的一門語言,關(guān)系代數(shù)主要是“集合”。

sql語句形式:select .... from ....

集合在sql當(dāng)中的表現(xiàn)形式:每一個select語句都是一個集合,寫在from后面的每個表、子查詢、視圖可以算作一個集合。

第一種情況
第二種情況
第三種情況

2、笛卡爾積

? ? select * from table1,table2,table1存在a列m行,table12存在b列n行,最后形成的集合是(a+b)列,(m*n)行記錄。我們學(xué)計算機你會發(fā)現(xiàn)一個現(xiàn)象,越往前追溯,都會一個簡單模型,如果你把所有sql問題往前推,最后都會看到 “笛卡爾積”的身影。

? 我舉一個簡單的例子,SQL理論中會把選取字段這個操作叫作“投影(project) ”。我不知道大家有無想過這個問題,為什么叫“投影"這個概念,而不是叫其他名稱,因為任何sql語句其實到最后都是回歸一個“笛卡爾積”,你在選取字段操作,好似對“笛卡爾積”做了一次“投影"。

3、集合之間的關(guān)系

? ? 集合之間的關(guān)系 一對一、一對多(最頻繁)、多對多(幾乎不用),在數(shù)據(jù)庫表中通常用FOREIGN KEY表示一對多的關(guān)系 。為什么要關(guān)注它們之間的關(guān)系,主要寫sql的語句發(fā)現(xiàn)記錄重復(fù)現(xiàn)象,你一定要檢查是不是一對多,多對多之間的關(guān)系。但是當(dāng)sql語句復(fù)雜以后了,即便你分析清楚集合之間的關(guān)系,很可能出現(xiàn)記錄重復(fù)的現(xiàn)象,當(dāng)與你的預(yù)期不符,我們可以distinct去重。

五、SQL中實戰(zhàn)技巧

? ? ? 這次我不再分析如何去書寫一個sql語句,我相信大家多多少少會寫sql。我只是跟大家分享一下我掌握的技巧。

? 1、能少寫,就不要多寫(write less,do more)。為什么要這樣,第一個提高效率;第二個減少出錯幾率。舉例說明:假設(shè)我們寫內(nèi)連接語句。其實是有2種寫法,我推薦大家使用第一種寫法。

特別注意在oracle數(shù)據(jù)庫當(dāng)中,左連接、右連接有一種簡寫的方式。

? 2、為什么有時候別名需要增加雙引號。當(dāng)你的別名,包含特殊符號的時候,就要增加雙引號,比如+、-、*、/、(、)。

3、使用null注意事項。null指的是理論意義上的絕對的空,不指任何含義。所以空字串、空數(shù)組、空對象表示含義的空,不是null。所以null一般使用身份運算符 is,以示區(qū)分,is null或者is not null。像python是用is判斷,但是java,js中用==來判斷,有些編程語言對這個問題并沒有嚴(yán)格區(qū)分。

4、union 和union all之間的區(qū)別。union將兩個集合去掉重復(fù)記錄合并在一起,union all只是簡單合并在一起。

5、group by使用問題。有時候會發(fā)現(xiàn)聚合函數(shù),感覺數(shù)值明顯錯誤,先去掉group by 查看原始記錄,看where條件是否寫錯。

6、充分利用數(shù)據(jù)庫提供函數(shù),簡化sql書寫難度。舉例說明:同時統(tǒng)計采購物品A、B、C、D分類的小計

同時統(tǒng)計某個科室的出庫給中心藥房的基數(shù)、節(jié)約的小計。

? ? 當(dāng)然我不可能窮舉所有的技巧,我只是把我使用最多一些技巧分享給大家,精通sql需要大家長期實踐。

六、案例分析

? ? 我曾經(jīng)收到來自基層醫(yī)療機構(gòu)的多位小伙伴的求助,他們在寫sql的時候出現(xiàn)“卡殼”問題。其實不管使用oracle、mssql、mysql解決問題的原理思路都是一樣,只不過表現(xiàn)形式不同。以下分享協(xié)助小伙伴處理問題2個案例。

? ? 案例一:某小伙伴遇到數(shù)據(jù)上報問題,某個藥品入庫與出庫數(shù)據(jù)需要在同一行展示,因為“入庫與出庫”來源于不同的表,小伙伴用了一種最原始的方法來處理。小伙伴的解決方案,把“入庫數(shù)據(jù)”統(tǒng)計出來放入一個中間表,把“出庫數(shù)據(jù)”統(tǒng)計出來放入一個中間表,再將兩個中間表關(guān)聯(lián)查詢。

入庫
出庫

? ? 小伙伴感覺這樣處理比較麻煩,期望能用一條sql語句解決問題。我?guī)托』锇榉治鍪欠窨梢杂靡粭lsql搞定的可能性,第一,對于來自于不同來源數(shù)據(jù)“入庫”和“出庫”,相當(dāng)于不同的集合,可以使用union連起來;第二,union合并有個特點,要求兩個集合是相同字段類型,相同的字段的個數(shù),缺少的字段可以使用虛擬列來解決;第三,將union結(jié)果當(dāng)作子查詢(相當(dāng)于得到一個新的集合),再進行g(shù)roup by處理,可以完成整個操作。 最終sql語句部份截圖如下所示:

入庫補充虛擬列
出庫補充虛擬列
union當(dāng)作子查詢再進行g(shù)roup by

案例二:某小伙伴,制作檢驗視圖給第三方調(diào)用,當(dāng)某個檢驗結(jié)果,超過了正常范圍,顯示↑,↓,否則為空,如下圖所示。

需求
使用case when

? 小伙伴在百度搜尋很多資料或許也是看了我的文章,想到了可以用case when來解決這個問題,但是執(zhí)行過程中報“sql server 從數(shù)據(jù)類型varchar 轉(zhuǎn)換為 float時出錯”。

出錯信息

? 因為我對mssql不熟悉這個問題對于我來說還是有一點的難度。我的思考過程如下,既然是數(shù)據(jù)類型出錯,ISNUMERIC(b.lac13) > 0,這個條件嫌疑就很大,isnumeric沒有真正把“數(shù)字值”過濾干凈,我百度一下isnumeric返回值,只有兩個返回值1,0。我當(dāng)時敏銳感覺到問題就在這里,ISNUMERIC(b.lac13) > 0這種寫法本身就是一個“坑”,假設(shè)判斷ISNUMERIC(‘陰性’) 返回0,0>0就成立,convert去轉(zhuǎn)換的時候就會報“sql server 從數(shù)據(jù)類型varchar 轉(zhuǎn)換為 float時出錯”。

? 我叫小伙伴改成ISNUMERIC(b.lac13)? and CONVERT(float, b.LAC10) < CONVERT(float, b.lac13),再測試,果然問題就解決了。1代表true,0代表false這個習(xí)慣是從C語言那里繼承過來的。不過小伙伴有點擔(dān)心,如果ISNUMERIC(‘陰性’)? and CONVERT(float, ‘陰性’) 這樣判斷不是一樣有問題嗎?我了解小伙伴這個擔(dān)心,如果他掌握一個基礎(chǔ)知識,這種擔(dān)心是完全是多余的。什么意思,一般編程語言都會有一個if條件熔斷機制。舉例說明:條件1 and 條件2 and 條件3,假設(shè)條件1是false,就可以決定整個表達式的值,意味著條件2 , 條件3不會再去做判斷處理,就好像發(fā)生了“熔斷”。再比如:條件1 or 條件2 or 條件3,假設(shè)條件1是true,就可以決定整個表達式的值,意味著條件2 , 條件3不會再去做判斷處理。

? 如果小伙伴還是不放心,可以將條件改成ISNUMERIC(b.lac13) == 1,就不會存在理解不了這個問題了。

處理效果

七、總結(jié)

? ? 俗說“光說不練假把式”。多寫sql才能掌握真技術(shù),同時也要不停的跳出自己的“舒適區(qū)”。為什么有人干了10年,水平還是很菜,因為他只不過把有些事情重復(fù)干了10年而己,并沒有真的成長。每次寫sql的時候,能不能不用中間表、能不能再簡單一點,每次挑戰(zhàn)一下自己,完成同樣的效果。所謂的高手,大部分都在挑戰(zhàn)自己能力邊界。最后祝大家都從文中有所收獲,成為sql高手!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。