sql server numeric 可存几位小数_想成为优秀SQL高手?你就差这些细节
標(biāo)準(zhǔn)結(jié)構(gòu)化查詢語言(Structured Query Language)簡稱SQL,sql是我們?nèi)粘9ぷ髦惺褂米疃嘁豁?xiàng)技能,寫sql可以說是一個(gè)可以干到退休的技能。看似簡單,但要精通卻很難。 sql包括增、刪、改、查,創(chuàng)建表、刪除表、修改表等等內(nèi)容,我們今天所講的sql是一種狹義上select語句,這個(gè)使用最頻繁,也是最復(fù)雜的。寫一篇關(guān)于技術(shù)類的文章,既要深刻,又要通俗易懂,的確要耗費(fèi)我不少精力,如果大家覺得此文對你或者有需要的人有所幫助,整理不易,記得關(guān)注小編 歡迎您轉(zhuǎn)發(fā)!
一、sql會(huì)不會(huì)淘汰?
大家滿懷熱情點(diǎn)進(jìn)來學(xué)習(xí)一下sql,首先要搞清楚一個(gè)問題,sql會(huì)淘汰嗎?要回答這個(gè)問題,首先有必要了解sql發(fā)展背景,它是關(guān)系型數(shù)據(jù)庫誕生的產(chǎn)物,有時(shí)候不得不佩服這些先輩,當(dāng)關(guān)系型數(shù)據(jù)庫起步發(fā)展的時(shí)候,就制定了一個(gè)統(tǒng)一的操作標(biāo)準(zhǔn),就是SQL標(biāo)準(zhǔn),所有關(guān)系型數(shù)據(jù)庫(mysql/mssql/oracle)都會(huì)實(shí)現(xiàn)這個(gè)標(biāo)準(zhǔn),這也是為什么sql會(huì)長盛不衰的原因,所以sql會(huì)不會(huì)淘汰,要看關(guān)系型數(shù)據(jù)庫會(huì)不會(huì)淘汰?到目前為止沒有看到任何關(guān)系型數(shù)據(jù)庫淘汰的跡象,傳統(tǒng)關(guān)系型數(shù)據(jù)庫過渡到分布式關(guān)系型數(shù)據(jù)庫,這是未來極有可能發(fā)生的事。
你可能會(huì)問市面不是有一個(gè)nosql的東西?首先nosql翻譯成中文,不是”沒有sql“的意思,而是”不僅僅有sql,還有其它“,nosql是not only sql的簡稱。nosql說的一種補(bǔ)充,什么意思,sql主要處理結(jié)構(gòu)化的數(shù)據(jù),nosql主要處理非結(jié)構(gòu)化的數(shù)據(jù)。目前來說nosql沒有一個(gè)統(tǒng)一的標(biāo)準(zhǔn),都是按照用途來發(fā)展,比如鍵值(Key-Value)存儲(chǔ)數(shù)據(jù)庫, Redis;列存儲(chǔ)數(shù)據(jù)庫,Cassandra;文檔型數(shù)據(jù)庫, MongoDb;圖形(Graph)數(shù)據(jù)庫,Neo4J。
二、什么是IT高手
扎實(shí)理論基礎(chǔ)知識(shí),這是決定一個(gè)人水平飛得有多高。靈活運(yùn)用這個(gè)基礎(chǔ)知識(shí)(非常難),才決定一個(gè)人水平有多牛。為什么我會(huì)說經(jīng)常出現(xiàn)”卡殼“現(xiàn)象,有些看上去很難的問題,其實(shí)運(yùn)用一些基礎(chǔ)知識(shí)就可以解決,但是要做這一點(diǎn)非常困難。
我們通常對高手定義都是可以處理日常工作中一些難題,注意我說的是一些難題,不要期望解決所有的難題,什么是日常工作的難題?特點(diǎn)一:問題偶然出現(xiàn),無法重現(xiàn)問題;特點(diǎn)二,沒有明顯的邏輯錯(cuò)誤,沒有解決問題思路;特點(diǎn)三:問題本身就很難(比如數(shù)據(jù)結(jié)構(gòu)與算法)。比如,我們HIS里面醫(yī)技系統(tǒng)就有這樣一個(gè)難題一直無法解決,護(hù)士錄入A代碼記錄,后臺(tái)偶然間會(huì)保存B代碼記錄,半年時(shí)間偶然出現(xiàn)1,2次,但是我們在HIS程序里面各種極端操作測試,始終無法重現(xiàn)問題,實(shí)在令人不解!
在這里我分享一下曾經(jīng)處理過難題,你會(huì)驚訝的發(fā)現(xiàn),解決問題的方法很簡單,都是用的最基本的基礎(chǔ)知識(shí)解決的,但是你想到這種解決方法,非常不易!
第一個(gè)問題:使用netbeans開發(fā)環(huán)境,在書寫js函數(shù)queryStr的時(shí)候,按ctrl+shift+F格式化代碼的時(shí)候,偶然會(huì)出現(xiàn)結(jié)構(gòu)混亂,有時(shí)候發(fā)現(xiàn)導(dǎo)航器js未出現(xiàn)這個(gè)函數(shù),如下圖所示:
問題原因: 原來js代碼與html在同一個(gè)文件來寫的,原來在queryStr函數(shù)是包含動(dòng)態(tài)生成html代碼的片斷,雖然這個(gè)代碼放變量賦值里面,在格式化的時(shí)候,netbeans依然會(huì)檢測這個(gè)html是否合法,導(dǎo)致縮進(jìn)混亂,和導(dǎo)航器分析不出這個(gè)函數(shù)。我個(gè)人猜測格式化的底層實(shí)現(xiàn),將整個(gè)文檔解析,解析html標(biāo)簽,即便html標(biāo)簽寫在js字符串變量里面,如果沒有完整配對,依然會(huì)出問題。
解決方法:保證queryStr涉及的html字符完整,并且里面提及的函數(shù)必須聲明出來。
第二個(gè)問題:下面來分享mysql bug。通過mysqldump導(dǎo)出來sql腳本,測試還原過程中,出現(xiàn)[Err] 1064錯(cuò)誤,跟蹤到是以下語句出錯(cuò),百思不得其解,當(dāng)時(shí)寫進(jìn)數(shù)據(jù)庫沒有任何問題,為什么導(dǎo)出來,再導(dǎo)進(jìn)去的時(shí)候就報(bào)錯(cuò)。
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''
質(zhì)控科劉成章要求統(tǒng)計(jì)2018.04.01---2018-06-30門診醫(yī)生的收' at line 9
可能存在的原因:
UPDATE `info`.`fh_comm_detail` set `cl_proc` = ‘.....’ WHERE (`mxid` = '100005')
cl_proc后面的值當(dāng)中包含/*,*/注釋符號(hào),mysql去解析的時(shí)候,觸發(fā)bug,原本包含在‘’中字符串含義發(fā)生變化,導(dǎo)致語句報(bào)錯(cuò)。(但是我在mysql查詢分析器,怎么樣都模擬不出來這種錯(cuò)誤,就是偶然發(fā)生)。
解決方法:將/*注釋符號(hào)替換為其他字符即可,比如”--”,讓其不觸發(fā)解析注釋串。
問題三:聯(lián)網(wǎng)醫(yī)保金額與本地程序計(jì)算,有少數(shù)患者偶爾會(huì)存在金額不一致問題。翻看程序代碼左看右看,都沒有問題,如下所示。
lc_jine_sum = round(tab_1.tabpage_1.dw_1.getitemnumber(1,"jine_total"),2)
問題原因:我突然想起一個(gè)基礎(chǔ)知識(shí),計(jì)算機(jī)浮點(diǎn)數(shù)本身是不準(zhǔn)確的,每次運(yùn)算都有可能得出不同的結(jié)果,既然不準(zhǔn)確,為什么我們還會(huì)大規(guī)模使用計(jì)算機(jī)來解決問題,解決方法就是提高計(jì)算機(jī)處理精度,讓它無限逼近準(zhǔn)確。什么意思,我們大部分現(xiàn)實(shí)當(dāng)中,大部分都是計(jì)算到2位小數(shù),最多也是4位小數(shù),但是計(jì)算機(jī)就無所謂,10-20位都可以處理,10-20位小數(shù)精度再截取2-4位小數(shù),當(dāng)然就可以做到準(zhǔn)確無誤。大家是否遇到過這種問題,明明只有一位小數(shù),把這些數(shù)字加起來的時(shí)候,你會(huì)看到一長串小數(shù),這就是計(jì)算機(jī)內(nèi)部使用高精度計(jì)算的問題,如下圖所示。
計(jì)算機(jī)內(nèi)部使用高精度的小數(shù)(一般是10幾位以上),來解決小數(shù)不準(zhǔn)確的問題。所以我當(dāng)時(shí)就把代碼改了一下,果然改完以后,問題從此沒有出現(xiàn)過。這就是利用基礎(chǔ)知識(shí)去解決實(shí)際當(dāng)中的難題,你看得我寫的很簡單,其實(shí)想到這個(gè)方法是非常困難的。
lc_jine_sum =round(tab_1.tabpage_1.dw_1.getitemnumber(1,"jine_total"),4) //先取出 4 位小數(shù)
lc_jine_sum = round(lc_jine_sum,2) //再進(jìn)行 2 位小數(shù)四舍五入
三、解決一個(gè)sql問題基本思路
日常工作sql語句主要用途,臨時(shí)統(tǒng)計(jì)數(shù)據(jù)、后臺(tái)查數(shù)找問題原因、制作報(bào)表。拿到一個(gè)sql語句的問題首先我們先從業(yè)務(wù)角度分析,后臺(tái)是否存在數(shù)據(jù),它們是否存在相應(yīng)關(guān)聯(lián)?沒有數(shù)據(jù),沒有關(guān)聯(lián),后繼工作毫無意義。
舉例說明,患者用藥追蹤,統(tǒng)計(jì)患者用了哪個(gè)廠家哪個(gè)批次的藥品。統(tǒng)計(jì)的意義,如果發(fā)藥哪個(gè)批次有問題,可以精準(zhǔn)找到相關(guān)患者。第一個(gè)問題,后臺(tái)有數(shù)據(jù)嗎,有的。his里面基本上都有藥品出入庫、患者用藥數(shù)據(jù),但是藥品管理的廠家、批次,與患者用藥之間沒有關(guān)聯(lián)。這也是his系統(tǒng)里面的一個(gè)難題,目前我還沒有看到靠譜的解決方案。由上述可以得知,患者用藥追蹤,這個(gè)問題無法用sql解決。
其次,通常你拿到一個(gè)稍微復(fù)雜sql問題一般不能一步到位寫出來。別操之過急,學(xué)會(huì)化解問題。舉例說明,統(tǒng)計(jì)歷史連續(xù)某段時(shí)間內(nèi)每日在院人數(shù),假設(shè)his系統(tǒng)中沒有生成數(shù)據(jù)(每天將在院人數(shù)數(shù)據(jù)拷貝生成一個(gè)中間表數(shù)據(jù))。
第一步分解:假設(shè)你現(xiàn)在統(tǒng)計(jì)歷史某日(2020-03-01)的在院人數(shù),在院人數(shù) = (入院日期 <= 在院人數(shù) <= 出院日期) + 一直未出院的在院人數(shù)。
第二步分解:模擬生成連續(xù)某段時(shí)間,比如2020-03月份,再關(guān)聯(lián)生成每日在院人數(shù)
最后,需要驗(yàn)證統(tǒng)計(jì)出來的數(shù)據(jù)是否正確,經(jīng)過驗(yàn)證,統(tǒng)計(jì)出來的歷史在院數(shù)據(jù)是完全正確的,發(fā)現(xiàn)有個(gè)別出現(xiàn)1,2個(gè)人的誤差,是因?yàn)槿藶樾薷牧恕比朐喝掌凇?#xff0c;”出院日期“所致,如果你想檢驗(yàn)sql水平怎么樣,我給你一個(gè)判斷標(biāo)準(zhǔn),是否使用了中間表。嚴(yán)格來說,只要數(shù)據(jù)庫存在數(shù)據(jù),存在關(guān)聯(lián),就可以用sql語句查出來,如果你精通sql是不會(huì)用到中間表的。
四、SQL基礎(chǔ)理論知識(shí)
掌握基礎(chǔ)理論知識(shí)是成為SQL高手第一步,我不會(huì)照搬教科書式的講課,我只會(huì)講解我認(rèn)為你最應(yīng)該的掌握的3個(gè)知識(shí)點(diǎn)。
1、集合(Set)。我給大家一個(gè)簡單的概念,sql里面一切皆集合。SQL 以關(guān)系代數(shù)為基礎(chǔ)發(fā)展出來的一門語言,關(guān)系代數(shù)主要是“集合”。
sql語句形式:select .... from ....
集合在sql當(dāng)中的表現(xiàn)形式:每一個(gè)select語句都是一個(gè)集合,寫在from后面的每個(gè)表、子查詢、視圖可以算作一個(gè)集合。
第一種情況
第二種情況
第三種情況
2、笛卡爾積
select * from table1,table2,table1存在a列m行,table12存在b列n行,最后形成的集合是(a+b)列,(m*n)行記錄。我們學(xué)計(jì)算機(jī)你會(huì)發(fā)現(xiàn)一個(gè)現(xiàn)象,越往前追溯,都會(huì)一個(gè)簡單模型,如果你把所有sql問題往前推,最后都會(huì)看到 “笛卡爾積”的身影。
我舉一個(gè)簡單的例子,SQL理論中會(huì)把選取字段這個(gè)操作叫作“投影(project) ”。我不知道大家有無想過這個(gè)問題,為什么叫“投影"這個(gè)概念,而不是叫其他名稱,因?yàn)槿魏蝧ql語句其實(shí)到最后都是回歸一個(gè)“笛卡爾積”,你在選取字段操作,好似對“笛卡爾積”做了一次“投影"。
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中實(shí)戰(zhàn)技巧
這次我不再分析如何去書寫一個(gè)sql語句,我相信大家多多少少會(huì)寫sql。我只是跟大家分享一下我掌握的技巧。
1、能少寫,就不要多寫(write less,do more)。為什么要這樣,第一個(gè)提高效率;第二個(gè)減少出錯(cuò)幾率。舉例說明:假設(shè)我們寫內(nèi)連接語句。其實(shí)是有2種寫法,我推薦大家使用第一種寫法。
特別注意在oracle數(shù)據(jù)庫當(dāng)中,左連接、右連接有一種簡寫的方式。
2、為什么有時(shí)候別名需要增加雙引號(hào)。當(dāng)你的別名,包含特殊符號(hào)的時(shí)候,就要增加雙引號(hào),比如+、-、*、/、(、)。
3、使用null注意事項(xiàng)。null指的是理論意義上的絕對的空,不指任何含義。所以空字串、空數(shù)組、空對象表示含義的空,不是null。所以null一般使用身份運(yùn)算符 is,以示區(qū)分,is null或者is not null。像python是用is判斷,但是java,js中用==來判斷,有些編程語言對這個(gè)問題并沒有嚴(yán)格區(qū)分。
4、union 和union all之間的區(qū)別。union將兩個(gè)集合去掉重復(fù)記錄合并在一起,union all只是簡單合并在一起。
5、group by使用問題。有時(shí)候會(huì)發(fā)現(xiàn)聚合函數(shù),感覺數(shù)值明顯錯(cuò)誤,先去掉group by 查看原始記錄,看where條件是否寫錯(cuò)。
6、充分利用數(shù)據(jù)庫提供函數(shù),簡化sql書寫難度。舉例說明:同時(shí)統(tǒng)計(jì)采購物品A、B、C、D分類的小計(jì)
同時(shí)統(tǒng)計(jì)某個(gè)科室的出庫給中心藥房的基數(shù)、節(jié)約的小計(jì)。
當(dāng)然我不可能窮舉所有的技巧,我只是把我使用最多一些技巧分享給大家,精通sql需要大家長期實(shí)踐。
六、案例分析
我曾經(jīng)收到來自基層醫(yī)療機(jī)構(gòu)的多位小伙伴的求助,他們在寫sql的時(shí)候出現(xiàn)“卡殼”問題。其實(shí)不管使用oracle、mssql、mysql解決問題的原理思路都是一樣,只不過表現(xiàn)形式不同。以下分享協(xié)助小伙伴處理問題2個(gè)案例。
案例一:某小伙伴遇到數(shù)據(jù)上報(bào)問題,某個(gè)藥品入庫與出庫數(shù)據(jù)需要在同一行展示,因?yàn)椤叭霂炫c出庫”來源于不同的表,小伙伴用了一種最原始的方法來處理。小伙伴的解決方案,把“入庫數(shù)據(jù)”統(tǒng)計(jì)出來放入一個(gè)中間表,把“出庫數(shù)據(jù)”統(tǒng)計(jì)出來放入一個(gè)中間表,再將兩個(gè)中間表關(guān)聯(lián)查詢。
入庫
出庫
小伙伴感覺這樣處理比較麻煩,期望能用一條sql語句解決問題。我?guī)托』锇榉治鍪欠窨梢杂靡粭lsql搞定的可能性,第一,對于來自于不同來源數(shù)據(jù)“入庫”和“出庫”,相當(dāng)于不同的集合,可以使用union連起來;第二,union合并有個(gè)特點(diǎn),要求兩個(gè)集合是相同字段類型,相同的字段的個(gè)數(shù),缺少的字段可以使用虛擬列來解決;第三,將union結(jié)果當(dāng)作子查詢(相當(dāng)于得到一個(gè)新的集合),再進(jìn)行g(shù)roup by處理,可以完成整個(gè)操作。 最終sql語句部分截圖如下所示:
入庫補(bǔ)充虛擬列
出庫補(bǔ)充虛擬列
union當(dāng)作子查詢再進(jìn)行g(shù)roup by
案例二:某小伙伴,制作檢驗(yàn)視圖給第三方調(diào)用,當(dāng)某個(gè)檢驗(yàn)結(jié)果,超過了正常范圍,顯示↑,↓,否則為空,如下圖所示。
需求
使用case when
小伙伴在百度搜尋很多資料或許也是看了我的文章,想到了可以用case when來解決這個(gè)問題,但是執(zhí)行過程中報(bào)“sql server 從數(shù)據(jù)類型varchar 轉(zhuǎn)換為 float時(shí)出錯(cuò)”。
出錯(cuò)信息
因?yàn)槲覍ssql不熟悉這個(gè)問題對于我來說還是有一定的難度。我的思考過程如下,既然是數(shù)據(jù)類型出錯(cuò),ISNUMERIC(b.lac13) > 0,這個(gè)條件嫌疑就很大,isnumeric沒有真正把“數(shù)字值”過濾干凈,我百度一下isnumeric返回值,只有兩個(gè)返回值1,0。我當(dāng)時(shí)敏銳感覺到問題就在這里,ISNUMERIC(b.lac13) > 0這種寫法本身就是一個(gè)“坑”,假設(shè)判斷ISNUMERIC(‘陰性’) 返回0,0>0就成立,convert去轉(zhuǎn)換的時(shí)候就會(huì)報(bào)“sql server 從數(shù)據(jù)類型varchar 轉(zhuǎn)換為 float時(shí)出錯(cuò)”。
我叫小伙伴改成ISNUMERIC(b.lac13) and CONVERT(float, b.LAC10) < CONVERT(float, b.lac13),再測試,果然問題就解決了。1代表true,0代表false這個(gè)習(xí)慣是從C語言那里繼承過來的。不過小伙伴有點(diǎn)擔(dān)心,如果ISNUMERIC(‘陰性’) and CONVERT(float, ‘陰性’) 這樣判斷不是一樣有問題嗎?我了解小伙伴這個(gè)擔(dān)心,如果他掌握一個(gè)基礎(chǔ)知識(shí),這種擔(dān)心是完全是多余的。什么意思,一般編程語言都會(huì)有一個(gè)if條件熔斷機(jī)制。舉例說明:條件1 and 條件2 and 條件3,假設(shè)條件1是false,就可以決定整個(gè)表達(dá)式的值,意味著條件2 , 條件3不會(huì)再去做判斷處理,就好像發(fā)生了“熔斷”。再比如:條件1 or 條件2 or 條件3,假設(shè)條件1是true,就可以決定整個(gè)表達(dá)式的值,意味著條件2 , 條件3不會(huì)再去做判斷處理。
如果小伙伴還是不放心,可以將條件改成ISNUMERIC(b.lac13) == 1,就不會(huì)存在理解不了這個(gè)問題了。
處理效果
七、總結(jié)
俗說“光說不練假把式”。多寫sql才能掌握真技術(shù),同時(shí)也要不停的跳出自己的“舒適區(qū)”。為什么有人干了10年,水平還是很菜,因?yàn)樗徊贿^把有些事情重復(fù)干了10年而己,并沒有真的成長。每次寫sql的時(shí)候,能不能不用中間表、能不能再簡單一點(diǎn),每次挑戰(zhàn)一下自己,完成同樣的效果。所謂的高手,大部分都在挑戰(zhàn)自己能力邊界。最后祝大家都從文中有所收獲,成為sql高手!
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的sql server numeric 可存几位小数_想成为优秀SQL高手?你就差这些细节的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对pca降维后的手写体数字图片数据分类_
- 下一篇: linux cmake编译源码,linu