日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

[MSSQL]COALESCE与ISNULL函数

發(fā)布時(shí)間:2023/11/29 数据库 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [MSSQL]COALESCE与ISNULL函数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

同事的一道面試題:

如何將某表中的某字段以逗號(hào)分隔拼接起來(lái)

在給出答案前,先給出測(cè)試用數(shù)據(jù),與之前的幾篇一樣:

--DROP TABLE T CREATE TABLE T(GRP_A VARCHAR(20),GRP_B VARCHAR(20),GRP_C VARCHAR(20),VAL INT) INSERT INTO T(GRP_A,GRP_B,GRP_C,VAL) SELECT 'a1','b1','c1',10 union all SELECT 'a1','b1','c2',10 union all SELECT 'a1','b2','c2',40 union all SELECT 'a1','b2','c3',40 union all SELECT 'a1','b2','c3',50 union all ? SELECT 'a2','b3','c3',12 union all SELECT 'a2','b3','c3',22 union all SELECT 'a2','b3','c3',32 ? SELECT * FROM T ? GRP_A GRP_B GRP_C VAL -------------------- -------------------- -------------------- ----------- a1 b1 c1 10 a1 b1 c2 10 a1 b2 c2 40 a1 b2 c3 40 a1 b2 c3 50 a2 b3 c3 12 a2 b3 c3 22 a2 b3 c3 32 ? (8 行受影響)


答案1:使用COALESCE函數(shù)

DECLARE @T NVARCHAR(200) --SET @T = '' SELECT @T = COALESCE(@T,'') + GRP_A + ',' FROM T SELECT @T ? 輸出結(jié)果 ------------------------ a1,a1,a1,a1,a1,a2,a2,a2,
答案2:使用ISNULL函數(shù) DECLARE @T NVARCHAR(200) --SET @T = '' SELECT @T = ISNULL(@T,'') + GRP_A + ',' FROM T SELECT @T ? 輸出結(jié)果與上邊的一致哈不貼了


實(shí)際上,您應(yīng)該已經(jīng)發(fā)現(xiàn)了,這兩個(gè)函數(shù)其實(shí)是個(gè)障眼術(shù),即只要我的@T變量有初始化,完全可以直接拼接,算是答案3吧,代碼如下:

DECLARE @T NVARCHAR(200) SET @T = '' SELECT @T = @T + GRP_A + ',' FROM T SELECT @T ? 輸出結(jié)果與上上例一致不貼了


因?yàn)槲覀冎?在SQL中NULL表示UNKNOW類型,與任務(wù)字符串累加都會(huì)得到NULL值,如

DECLARE @T NVARCHAR(200) SET @T = NULL SET @T = @T + 'hello world' --PRINT @T這里不用PRINT是因?yàn)榭床坏綄?shí)際輸出什么 SELECT @T ? 實(shí)際輸出 ---- NULL


那么,再回來(lái)看上述所謂的答案1,2,3都不夠嚴(yán)謹(jǐn)!即,如果該表中有那么一行,它的字段為NULL,會(huì)怎么辦?!

答案3最終會(huì)返回NULL,答案1和答案2則跳過(guò)NULL值所在行以前所有的數(shù)據(jù),返回NULL行以下的累加!所以嘞?要對(duì)GRP_A列進(jìn)行是否是NULL值的驗(yàn)證!

實(shí)事上,COALESCE函數(shù)與ISNULL函數(shù)原本就是這個(gè)功能:返回表達(dá)式中第一個(gè)不為NULL的值,所謂障眼術(shù)即指此

下邊的SQL腳本演示了兩個(gè)函數(shù)的基本功能:

SET NOCOUNT ON DECLARE @T CHAR(6) SELECT 'COALESCE',COALESCE(@T,NULL,NULL,'1234567890') SELECT 'ISNULL',ISNULL(@T,'1234567890') ? 輸出結(jié)果 -------- ---------- COALESCE 1234567890 ? ------ ------ ISNULL 123456


先聲明了一個(gè)類型為CHAR(6)的變量@T,沒有設(shè)置值,默認(rèn)為NULL

然后分別調(diào)用了ISNULL函數(shù)和COALESCE函數(shù),ISNULL返回了符合變量定義類型的值,即截?cái)嗪鬄镃HAR(6)類型,而COALESCE則返回完完整整的字符串

簡(jiǎn)單對(duì)比下兩個(gè)函數(shù)

兩個(gè)函數(shù)都返回第一個(gè)不為空的表達(dá)式,

其一,ISNULL考慮變量類型,而COALESCE則不考慮

其二,ISNULL只接收兩個(gè)參數(shù),而COALESCE則可以接收多個(gè)參數(shù)

再回來(lái)看那個(gè)面試題,

如何將某表中的某字段以逗號(hào)分隔拼接起來(lái)?

答案4:

DECLARE @T NVARCHAR(200) ? SET @T = '' SELECT @T = @T + ISNULL(GRP_A,'NULL') + ',' FROM T SELECT @T

面試題這一部分結(jié)束,來(lái)看看ISNULL函數(shù)的應(yīng)用實(shí)例

1,利用ISNULL函數(shù)干掉OR運(yùn)算!

題目是查詢表中VAL小于20的值,包括NULL值:

SELECT * FROM T WHERE ISNULL(VAL,-1) < 20 SELECT * FROM T WHERE VAL IS NULL OR VAL < 20 ? 兩個(gè)SQL具有相同的輸出結(jié)果 GRP_A GRP_B GRP_C VAL -------------------- -------------------- -------------------- ----------- a1 b1 c1 10 a1 b1 c2 10 a2 b3 c3 NULL a2 b3 c3 NULL a2 b3 c3 NULL ? (5 行受影響) ? GRP_A GRP_B GRP_C VAL -------------------- -------------------- -------------------- ----------- a1 b1 c1 10 a1 b1 c2 10 a2 b3 c3 NULL a2 b3 c3 NULL a2 b3 c3 NULL ? (5 行受影響)


2,ISNULL非主流更新表存儲(chǔ)過(guò)程示例

如某更新表存儲(chǔ)過(guò)程如下:

CREATE PROC UpdateT( @ID INT, @GRP_A VARCHAR(10) = NULL, @GRP_B VARCHAR(10) = NULL, @GRP_C VARCHAR(10) = NULL, @VAL INT = 0 )AS BEGIN UPDATE T SET GRP_A = @GRP_A, GRP_B = @GRP_B, GRP_C = @GRP_C, VAL = @VAL WHERE ID = @ID END

當(dāng)我們使用這個(gè)存儲(chǔ)過(guò)程的時(shí)候,必須先得該行的所有記錄,再把所有記錄更新回去,可是這并不總是必須的

有時(shí)候手頭只有兩個(gè)數(shù)據(jù):ID和VAL,我只想更新這個(gè)VAL

又有時(shí)候手頭有另外兩個(gè)數(shù)據(jù):ID和GRP_A,這時(shí)候只更新GRP_A列即可

還有很多情況,如僅更新GRP_A,

僅更新GRP_A,GRP_B

僅更新GRP_A,GRP_B,GRP_C

僅更新GRP_A,GRP_B,GRP_C,VAL

...

這樣的組合太多了,要想一勞永逸解決問(wèn)題那就得更新任何字段前,先得到整行記錄,再整行更新回去,于是多了一項(xiàng)工作:先查詢,再更新

不爽不爽,那沒有辦法不先查詢直接更新某一列呢?而且列可以任意組合?

在給出答案前,先聲明一句:這個(gè)方法算不上完美解決方案,僅僅是個(gè)思路罷了,雖然我一直認(rèn)為沒什么影響,但如果要在正式項(xiàng)目中使用,建議還是多聽聽DBA的意見!

非主流更新任意列存儲(chǔ)過(guò)程:

CREATE PROC UpdateT( @ID INT, @GRP_A VARCHAR(10) = NULL, @GRP_B VARCHAR(10) = NULL, @GRP_C VARCHAR(10) = NULL, @VAL INT = 0 )AS BEGIN UPDATE T SET GRP_A = ISNULL(@GRP_A,GRP_A), GRP_B = ISNULL(@GRP_B,GRP_B), GRP_C = ISNULL(@GRP_C,GRP_C), VAL = ISNULL(@VAL,VAL) WHERE ID = @ID END

解讀1上邊的這個(gè)存儲(chǔ)過(guò)程,假設(shè)參數(shù)@GRP_A為NULL時(shí),經(jīng)過(guò)ISNULL運(yùn)算返回了GRP_A列!即實(shí)際變成了

SET GRP_A = ISNULL(NULL,GRP_A)

再演變?yōu)镾ET GRP_A = GRP_A!神馬意思?什么也沒更新…把自己更新為自己,等什么也沒干,空忙活一場(chǎng)!但是

我們的效果達(dá)到了!@GRP_A參數(shù)為NULL時(shí)(不傳遞該參數(shù),在定義存儲(chǔ)過(guò)程時(shí)已經(jīng)設(shè)計(jì)為可選參數(shù)),自己更新自己

當(dāng)該參數(shù)不為NULL時(shí),進(jìn)行了實(shí)際的更新,其余三列以此類推,除@ID參數(shù)必須要傳外,其它參數(shù)都是可選的!誰(shuí)有值就更新誰(shuí),

什么模式?門面模式(又稱外觀模式),把小碎操作變成一個(gè)大的操作

解讀2為什么第二部分都使用了ISNULL而不是COALESCE函數(shù)?

原因正是ISNULL會(huì)考慮第一個(gè)參數(shù)的類型聲明從而自動(dòng)截?cái)喑L(zhǎng)部分?jǐn)?shù)據(jù)!

如果用COALESCE的話可能會(huì)導(dǎo)致返回結(jié)果超出列定義!

產(chǎn)生將截?cái)喽M(jìn)制字符串錯(cuò)誤


供討論

總結(jié)

以上是生活随笔為你收集整理的[MSSQL]COALESCE与ISNULL函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。