sqlserver ISNULL两个参数位数不一致的陷阱

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39541395/article/details/83450697

大家先看下面一个小例子

A表的a字段:
A.a:varchar(8) = null;
B表的b字段:
B.b:varchar(10) = 1234567890;
执行 ISNUL(A.a,B.b) as test

那么上面sql返回的结果是什么呢?大家是不是认为是“1234567890”
哈哈,“1234567890”结果是不对的,正确的结果是“12345678”

结论:
使用sqlserver的ISNULL函数的时候,如果满足下面2个情况
・第一个参数的在表里面定义的位数和第二个参数在表里面定义的位数不一致,并且第二个参数的位数大于第一个参数的位数
・第一个参数是NULL

那么,返回结果肯定和第一个参数定义的位数为准。

展开阅读全文

[原创]SQLServer陷阱

06-10

本文旨在指出一些在使用SQLServer过程中容易犯的错误, 希望能给您带来帮助.rn若没有特殊说明, 本文是指在MS SQLServer 2000简体中文版的默认配置环境中.rnrn一, NULL与布尔数据类型rnTransact-SQL中存在Boolean类型, if 后面的表达式的计算结果一般是Boolean类型, 但无法使用 declare 定义Boolean类型的变量.rnrnBoolean数据类型有三种取值, TRUE, FALSE, UNKNOWN, 第3种取值通常会被人忽视从而导致逻辑错误.rn默认情况下SET ANSI_NULLS为ON, 在逻辑表达式中如果你忽略了NULL的存在, 结果可能会异于你所想.rn例1: rn[code=SQL]rndeclare @a intrnif (@a > 0)rn set @a = 1rnelse if not (@a > 0)rn set @a = 2rnelsern set @a = 3rn[/code]rn结果@a的值应该是3, 因为NULL>0的值为UNKNOWN, NOT UNKNOWN的值还为UNKNOWN.rn例2:rn[code=SQL]rndeclare @a intrnif @a = nullrn set @a = 1rnelse if @a = null or 1 = 1rn set @a = 2rnelsern set @a = 3rn[/code]rn结果@a的值应该是2, 因为NULL = 0的值为UNKNOWN, UNKNOWN or TRUE的值为TRUE.rnrn二, 运行时错误与自动回滚事务rn有些人认为一个批查询在执行中发生了错误, 这个查询就会中止, 其实是错误的.rnrn例1:rn[code=SQL]rndeclare @i intrnset @i = 1 / 0rnset @i = 1rnselect @irn[/code]rn结果会先报一个rn服务器: 消息 8134,级别 16,状态 1,行 2rn遇到被零除错误。rn然后输出结果集 1.rnrn例2:rn[code=SQL]rnset xact_abort onrndeclare @i intrnset @i = 1 / 0rnset @i = 1rnselect @irn[/code]rn结果只报错, 不会输出结果.rnrn例3:rn请在查询分析器中新建连接执行rn[code=SQL]rncreate table table1(id int primary key)rnrnbegin tranrninsert into table1 values (1)rninsert into table1 values (1)rninsert into table1 values (2)rncommit tranrn[/code]rn第二个insert会产生违反主键约束错误, 但是执行结束后你会发现事务已经提交并且table1中已经有两行记录1与2rnrn例4:rn[code=SQL]rnset xact_abort onrnrncreate table table2(id int primary key)rnrnbegin tranrninsert into table2 values (1)rninsert into table2 values (1)rninsert into table2 values (2)rncommit tranrn[/code]rn执行结束后, table2中没有记录, 说明事务已经回滚.rnrn当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句产生运行时错误,整个事务将终止并回滚。为 OFF 时,只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。编译错误rnrn(如语法错误)不受 SET XACT_ABORT 的影响。rn一般批查询中 SET XACT_ABORT 默认为 OFF, 隐式开启的事务如触发器中SET XACT_ABORT 默认为ONrnrn未完... 论坛

typedef的四个用途和两个陷阱

01-16

rn用途一:rn定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:rnchar* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, rn// 和一个字符变量;rn以下则可行:rntypedef char* PCHAR; // 一般用大写rnPCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针rn虽然:rnchar *pa, *pb;rn也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。rnrn用途二:rn用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:rnstruct tagPOINT1rnrn int x;rn int y;rn;rnstruct tagPOINT1 p1; rnrn而在C++中,则可以直接写:结构名 对象名,即:rntagPOINT1 p1;rnrn估计某人觉得经常多写一个struct太麻烦了,于是就发明了:rntypedef struct tagPOINTrnrn int x;rn int y;rnPOINT;rnrnPOINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候rnrn或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。rnrn用途三:rn用typedef来定义与平台无关的类型。rn比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:rntypedef long double REAL; rn在不支持 long double 的平台二上,改为:rntypedef double REAL; rn在连 double 都不支持的平台三上,改为:rntypedef float REAL; rn也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。rn标准库就广泛使用了这个技巧,比如size_t。rn另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。rnrn用途四:rn为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:rnrn1. 原声明:int *(*a[5])(int, char*);rn变量名为a,直接用一个新别名pFun替换a就可以了:rntypedef int *(*pFun)(int, char*); rn原声明的最简化版:rnpFun a[5]; rnrn2. 原声明:void (*b[10]) (void (*)());rn变量名为b,先替换右边部分括号里的,pFunParam为别名一:rntypedef void (*pFunParam)();rn再替换左边的变量b,pFunx为别名二:rntypedef void (*pFunx)(pFunParam);rn原声明的最简化版:rnpFunx b[10];rnrn3. 原声明:doube(*)() (*e)[9]; rn变量名为e,先替换左边部分,pFuny为别名一:rntypedef double(*pFuny)();rn再替换右边的变量e,pFunParamy为别名二rntypedef pFuny (*pFunParamy)[9];rn原声明的最简化版:rnpFunParamy e; rnrn理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:rnint (*func)(int *p);rn首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。rnint (*func[5])(int *);rnfunc右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。rnrn也可以记住2个模式:rntype (*)(....)函数指针 rntype (*)[]数组指针 rn---------------------------------rnrn陷阱一:rn记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:rn先定义:rntypedef char* PSTR;rn然后:rnint mystrcmp(const PSTR, const PSTR);rnrnconst PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const。rn原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。rn简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。rnrn陷阱二:rntypedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:rntypedef static int INT2; //不可行rn编译将失败,会提示“指定了一个以上的存储类”。rnrn探讨C++编程的个人博客:rnblog.sina.com.cn/m/hzm 论坛

没有更多推荐了,返回首页