[MSSQL]COALESCE与ISNULL函数

同事的一道面试题:

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

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

--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的话可能会导致返回结果超出列定义!

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


供讨论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404986.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

onvif规范 中文介绍

From: http://blog.csdn.net/ghostyu/article/details/8162193 什么是ONVIF ? ONVIF规范描述了网络视频的模型、接口、数据类型以及数据交互的模式。并复用了一些现有的标准&#xff0c;如WS系列标准等。 ONVIF规范的目标是实现一个网络视频框架协议&#xff0c;使不同厂商所…

[react] React的render中可以写{if else}这样的判断吗?

[react] React的render中可以写{if else}这样的判断吗&#xff1f; 不可以&#xff0c;可以用 三元运算符或者 与运算符操作 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前…

sunspot 查询语法

demand_text:12实际当中是字段demand,sunspot生成的时候会生成&#xff0c;demand_textsunspot内置的solr的版本http://127.0.0.1:8982/solr/admin/registry.jspSolr Specification Version: 1.4.0Solr Implementation Version: 1.4.0 833479 - grantingersoll - 2009-11-06 12…

gsoap使用总结

From: http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html >>用C实现WebService&#xff0c;gsoap是最好的选择了。近一个月都在折腾这个&#xff0c;做个总结吧&#xff0c;估计会写得比较长。因为其中碰到了不少问题&#xff0c;但最终都解决调了。 >…

[react] 使用React的memo和forwardRef包装的组件为什么提示children类型不对?

[react] 使用React的memo和forwardRef包装的组件为什么提示children类型不对&#xff1f; 过去使用Component、FC等类型定义组件时一般不需要我们定义props里children的类型&#xff0c;因为在上述类型里已经帮你默认加上了 { children?: ReactNode } 的定义。但是types/reac…

2011阿里巴巴程序设计公开赛 / 1002 Fruit Ninja

某神的代码&#xff1a; #include<stdio.h> #define max(x,y) (x)>(y)?(x):(y) #define min(x,y) (x)<(y)?(x):(y) const int inf0x7fffffff;struct node // Fruit {int adv;int x[11],y[11]; }Fruit[11];int Fruit_num,ans;//---- int judge( int x1…

绑定注意事项——数据源的属性

&#xff08;一&#xff09;属性的绑定总结&#xff08;以下属性均指“数据源的属性”&#xff09;&#xff1a; 1&#xff1a;属性的绑定&#xff08;单体属性和集合属性&#xff09;&#xff1a; 若要 将属性值或引用 的变化 通知给UI&#xff0c;则要求属性具有改变通知的功…

[react] 怎样将多个组件嵌入到一个组件中?

[react] 怎样将多个组件嵌入到一个组件中&#xff1f; import A from /* 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Bash脚本报错:“/bin/bash^M: bad interpreter: No such file or directory”

1、问题 github下载一个源码&#xff0c;运行install脚本时&#xff08;# ./myinstal_cp&#xff09;一直报错“/bin/bash^M: bad interpreter: No such file or directory”&#xff0c;如&#xff1a; -bash: ./myinstall_cp: /bin/bash^M: bad interpreter: No such file …

16、常用shell命令方法

1、shell基本 2、父shell在执行shell命令时&#xff0c;通常是创建子shell&#xff0c;继承父shell环境&#xff0c;执行命令&#xff0c;退出&#xff0c;相关环境销毁&#xff1b;父shell得到子shell的退出状态。 通过命令.或source来使其有当前环境中执行&#xff0c;而不创…

Linux学习之exit函数

From: http://hi.baidu.com/homappy/item/549b37c06865877488ad9e75 若父进程在子进程之前终止了&#xff0c;则子进程的父进程将变为init进程&#xff0c;其PID为1&#xff1b;保证每个进程都有父进程。 Linux学习之"exit函数" 先看下"_exit"和"ex…

为什么要设置环境变量,环境变量有什么用?

比如说你要执行 java 命令&#xff0c;你不设置环境变量path包括你的jdk安装路径&#xff0c;那系统去哪找你的java.exe文件。 如果执行某个命令&#xff0c;系统无法在当前文件夹里找到对应的.exe&#xff0c;那么系统就会去path包含的路径找挨个找看是否能知道对应的.exe&…

CM3计算板RTC闹钟唤醒系统

1、前言 一个周期性控制系统的核心为CM3计算板&#xff0c;在电池供电情况下要求尽可能提高使用时长。由于系统空闲时长较多&#xff0c;因此在考虑低功耗的情况下将系统关机以进一步降低功耗。需要注意的是&#xff0c;系统关机后需要在指定时间唤醒&#xff0c;继续执行相关…

[react] 在React中如果去除生产环境上的sourcemap?

[react] 在React中如果去除生产环境上的sourcemap&#xff1f; GENERATE_SOURCEMAPfalse react-scripts buildIf you use the Create-React-APP 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目…

[相关总结性文章] 写给即将入行的程序员的一封信

本文来自&#xff1a;安卓航班网 首先&#xff0c;欢迎来到程序员的世界。在这个世界上&#xff0c;不是有很多人想创造软件并解决问题。你是一名hacker&#xff0c;属于那些愿意做一些有挑战性的事情的人。  “当你不创造东西时&#xff0c;你只会根据自己的感觉而不是能力去…

火狐浏览器所有的快捷键

From: http://zhidao.baidu.com/question/218604936.html firefox快捷键搜索类&#xff1a;本页查找&#xff1a; CtrlF 再次查找&#xff1a; F3 输入查找链接&#xff1a; 输入查找文本&#xff1a; / 查找&#xff1a; ShiftF3 网页搜索&#xff1a; CtrlK 或 CtrlEfire…

超文本引用href的几种用法

href"要跳转目标链接"; href"#";当前页面不跳转&#xff08;返回顶部&#xff09; href"###";当前页面不跳转&#xff08;同时不回到顶部&#xff09; href"javascript:;";当前页面不跳转&#xff0c;返回空 href"javscript:void…

[react] React的触摸事件有哪几种?

[react] React的触摸事件有哪几种&#xff1f; onTouchCancel onTouchEnd onTouchMove onTouchStart 个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

arm-linux-gnueabihf gcc8.3交叉编译工具搭建教程

一、运行环境 1.1 执行机环境 ld GNU ld (GNU Binutils for Raspbian) 2.31.1 ldd ldd (Debian GLIBC 2.28-10rpi1) 2.28 Copyright (C) 2018 Free Software Foundation, Inc. gcc (Raspbian 8.3.0-6rpi1) 8.3.0 Copyright (C) 2018 Free Software Foundation, Inc.…

Md5 Md5实现原理

参考&#xff1a; http://wenku.baidu.com/view/ddb1008271fe910ef12df8df.html转载于:https://www.cnblogs.com/85538649/archive/2011/08/24/2152187.html