同事的一道面试题:

如何将某表中的某字段以逗号分隔拼接起来

在给出答案前,先给出测试用数据,与之前的几篇一样:

--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函数

DECLARE @T NVARCHAR(200)
--SET @T = ''
SELECT @T = COALESCE(@T,'') + GRP_A + ',' FROM T
SELECT @T
 
输出结果
------------------------
a1,a1,a1,a1,a1,a2,a2,a2,

答案2:使用ISNULL函数

DECLARE @T NVARCHAR(200)
--SET @T = ''
SELECT @T = ISNULL(@T,'') + GRP_A + ',' FROM T
SELECT @T
 
输出结果与上边的一致哈不贴了

实际上,您应该已经发现了,这两个函数其实是个障眼术,即只要我的@T变量有初始化,完全可以直接拼接,算是答案3吧,代码如下:

DECLARE @T NVARCHAR(200)
SET @T = ''
SELECT @T = @T + GRP_A + ',' FROM T
SELECT @T
 
输出结果与上上例一致不贴了

因为我们知道,在SQL中NULL表示UNKNOW类型,与任务字符串累加都会得到NULL值,如

DECLARE @T NVARCHAR(200)
SET @T = NULL
SET @T = @T + 'hello world'
--PRINT @T这里不用PRINT是因为看不到实际输出什么
SELECT @T
 
实际输出
----
NULL

那么,再回来看上述所谓的答案1,2,3都不够严谨!即,如果该表中有那么一行,它的字段为NULL,会怎么办?!

答案3最终会返回NULL,答案1和答案2则跳过NULL值所在行以前所有的数据,返回NULL行以下的累加!所以嘞?要对GRP_A列进行是否是NULL值的验证!

实事上,COALESCE函数与ISNULL函数原本就是这个功能:返回表达式中第一个不为NULL的值,所谓障眼术即指此

下边的SQL脚本演示了两个函数的基本功能:

SET NOCOUNT ON
DECLARE @T CHAR(6)
SELECT 'COALESCE',COALESCE(@T,NULL,NULL,'1234567890')
SELECT 'ISNULL',ISNULL(@T,'1234567890')
 
输出结果
-------- ----------
COALESCE 1234567890
 
------ ------
ISNULL 123456

先声明了一个类型为CHAR(6)的变量@T,没有设置值,默认为NULL

然后分别调用了ISNULL函数和COALESCE函数,ISNULL返回了符合变量定义类型的值,即截断后为CHAR(6)类型,而COALESCE则返回完完整整的字符串

简单对比下两个函数

两个函数都返回第一个不为空的表达式,

其一,ISNULL考虑变量类型,而COALESCE则不考虑

其二,ISNULL只接收两个参数,而COALESCE则可以接收多个参数

再回来看那个面试题,

如何将某表中的某字段以逗号分隔拼接起来?

答案4:

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

面试题这一部分结束,来看看ISNULL函数的应用实例

1,利用ISNULL函数干掉OR运算!

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

SELECT * FROM T WHERE ISNULL(VAL,-1) < 20
SELECT * FROM T WHERE VAL IS NULL OR VAL < 20
 
两个SQL具有相同的输出结果
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非主流更新表存储过程示例

如某更新表存储过程如下:

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

当我们使用这个存储过程的时候,必须先得该行的所有记录,再把所有记录更新回去,可是这并不总是必须的

有时候手头只有两个数据:ID和VAL,我只想更新这个VAL

又有时候手头有另外两个数据:ID和GRP_A,这时候只更新GRP_A列即可

还有很多情况,如仅更新GRP_A,

仅更新GRP_A,GRP_B

仅更新GRP_A,GRP_B,GRP_C

仅更新GRP_A,GRP_B,GRP_C,VAL

...

这样的组合太多了,要想一劳永逸解决问题那就得更新任何字段前,先得到整行记录,再整行更新回去,于是多了一项工作:先查询,再更新

不爽不爽,那没有办法不先查询直接更新某一列呢?而且列可以任意组合?

在给出答案前,先声明一句:这个方法算不上完美解决方案,仅仅是个思路罢了,虽然我一直认为没什么影响,但如果要在正式项目中使用,建议还是多听听DBA的意见!

非主流更新任意列存储过程:

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上边的这个存储过程,假设参数@GRP_A为NULL时,经过ISNULL运算返回了GRP_A列!即实际变成了

SET GRP_A = ISNULL(NULL,GRP_A)

再演变为SET GRP_A = GRP_A!神马意思?什么也没更新…把自己更新为自己,等什么也没干,空忙活一场!但是

我们的效果达到了!@GRP_A参数为NULL时(不传递该参数,在定义存储过程时已经设计为可选参数),自己更新自己

当该参数不为NULL时,进行了实际的更新,其余三列以此类推,除@ID参数必须要传外,其它参数都是可选的!谁有值就更新谁,

什么模式?门面模式(又称外观模式),把小碎操作变成一个大的操作

解读2为什么第二部分都使用了ISNULL而不是COALESCE函数?

原因正是ISNULL会考虑第一个参数的类型声明从而自动截断超长部分数据!

如果用COALESCE的话可能会导致返回结果超出列定义!

产生将截断二进制字符串错误

供讨论

[MSSQL]COALESCE与ISNULL函数相关推荐

  1. COALESCE()、isnull()、nullif()函数的用法

    http://blog.csdn.net/baoshan/article/details/2907602 COALESCE() 用法 Select  COALESCE(null,null,'1','2 ...

  2. coalesce函数_什么是SQL Server COALESCE()函数?

    coalesce函数 Hey, folks! In this article, we will be focusing on SQL Server COALESCE() function. 嘿伙计! ...

  3. oracle同sql中isnull无法,SQL中的ISNULL函数使用介绍

    这篇文章主要为大家详细介绍了SQL中的ISNULL函数使用介绍,具有一定的参考价值,可以用来参考一下. 感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! ISNULL 使用指定的替换值替换 ...

  4. SQL中的ISNULL函数介绍

    SQL中有多种多样的函数,下面将为您介绍SQL中的ISNULL函数,包括其语法.注释.返回类型等,供您参考,希望对您学习SQL能够有所帮助. ISNULL 使用指定的替换值替换 NULL. 语法 IS ...

  5. oracle函数isnull,SQL中的ISNULL函数使用介绍

    ISNULL 使用指定的替换值替换 NULL. 语法 ISNULL ( check_expression , replacement_value ) 参数 check_expression 将被检查是 ...

  6. SQL中的ISNULL函数详解及用途

    SQL中有多种多样的函数,下面将为您介绍SQL中的ISNULL函数,包括其语法.注释.返回类型等,供您参考,希望对您学习SQL能够有所帮助 ISNULL 使用指定的替换值替换 NULL. 语法 ISN ...

  7. Orcale的NVL、NVL2函数和SQL Server的ISNULL函数

    Orcal 的 nvl函数 NVL(Expr1,Expr2)如果Expr1为NULL,返回Expr2的值,否则返回Expr1的值,Expr1,Expr2都为NULL则返回NULLNVL2(Expr1, ...

  8. oracle isnull的用法,SQL中的ISNULL函数使用介绍

    使用指定的替换值替换 NULL. 语法 ISNULL ( check_expression , replacement_value ) 参数 check_expression 将被检查是否为 NULL ...

  9. sql isnull函数的使用(转载)

    sql isnull函数的使用 ISNULL 使用指定的替换值替换 NULL. 语法 ISNULL ( check_expression , replacement_value ) 参数 check_ ...

最新文章

  1. PHP 安全email
  2. jq点击按钮打开和关闭弹出层,点击除了当前按钮以外的地方关闭弹出层
  3. DB2 SQL 递归实现多行合并
  4. 分布式事务,EventBus 解决方案:CAP【中文文档】
  5. 工作111:对element-form的理解
  6. 三个等价c语言表达式,C语言习题综合(20页)-原创力文档
  7. apache 添加下载文件头
  8. 【Linux】宝塔Linux面板命令大全
  9. BZOJ 2956 模积和
  10. BZOJ1101 洛谷3455:[POI2007]ZAP——题解
  11. Linux中的mate程序的进程,终端下以后台模式运行Linux程序的过程详解
  12. 毕业5年跳槽24次,为什么这届95后换工作越来越勤?
  13. 前端 JavaScript 复制粘贴的奥义——Clipboard 对象概述
  14. JAXB--@XmlElementWrapper注解(二)
  15. 万年历带日程提醒功能
  16. 计算机打开文件的原理,电脑删除文件是怎么实现的?它的原理是什么?
  17. 为什么文件删除了但磁盘空间没有释放?
  18. IMP ORA-20005: object statistics are locked(二)
  19. 三国志9如何进行城市防御
  20. jdk1.7.0_80下载与安装

热门文章

  1. mysql5.7初始密码查看及密码重置
  2. C++Primer学习笔记:第4章 表达式
  3. wait、waitpid
  4. 【VS C++ 2010】查看内存的方法详解
  5. Linux进程通信之mmap
  6. 覆盖所有面试知识点,赶紧收藏!
  7. [十二省联考2019]皮配
  8. POJ1204 Word Puzzles
  9. org.dom4j.DocumentException: null Nested exception: null解决方法
  10. HTTP基本认证(Basic Authentication)的JAVA示例