设为首页 收藏本站
查看: 1547|回复: 0

[经验分享] SQL Server Null的比较运算(转)

[复制链接]

尚未签到

发表于 2015-7-1 09:34:05 | 显示全部楼层 |阅读模式
  今天我在写sql的时候发现用

UPDATE dbo.tblInvTransaction
SET Area_Type = 'Gross',
WHERE (Area_Type  = null)

结果为零。


然后查到下面这个文章
改成

UPDATE dbo.tblInvTransaction
SET Area_Type = 'Gross'
WHERE (Area_Type is NULL )
就ok了



前几天写一个数据库查询程序,碰到的一个问题,是关于SQL Server的Null值的比较运算的。一般情况下我们查询空值或者非空值的时候,用的是is null/is not null,而很少用=/。但是在我的这个程序中,没有用is这样的关键字,而是用=/这样的比较元算符号,这就碰到了一些问题。
问题起源于一个Web查询页面,因为问题比较复杂的,所以简化一下来说明。
在页面上用户可以自由选择数据表的某些字段,填写该字段的查询条件,先是选择比较运算符号(=,等),然后填写值。提交之后,就需要创建一个SQL语句,查询条件的各部分由不同的程序模块创建。这里涉及两个程序模块,一个模块根据提交创建比较运算符号,一个模块负责创建比较值模块。在创建值模块中有这样一个规则,“如果提交的值是空的,把该值设为Null”。
但是我发现,如果比价值为Null的时候,同样一个SQL查询语句放在存储过程里边查询和通过应用程序直接查询的结果是不一样的。
查了查SQL Server文档,发现Null值的比较运算,存在两种规则:
在SQL2000中Null值的比较运算有两种规则。一种是ANSI SQL(SQL-92)规定的Null值的比较取值结果都为False,既Null=Null取值也是False。另一种不准循ANSI SQL标准,即Null=Null为True。
以一张表T的查询为例。
  表T存在下面的数据:
RowId Data
--------------
1 'test'
2 Null
3 'test1'
  按照ANSI SQL标准,下面的两个查询都不返回任何行:
Query1: select * from T where Data=null
Query2: select * from T where Datanull
而按照非ANSI SQL标准,查询1将返回第二行,查询2返回1、3行。
ANSI SQL标准中取得Null值的行需要用下面的查询:
select * from T where Data is null
反之则用is not null。由此可见非ANSI SQL标准中Data=Null等同于Data Is Null,DataNull等同于Data Is Not Null。
  而控制采用那一种规则,需要使用命令SET ANSI_NULLS [ON/OFF]。ON值采用ANSI SQL标准,OFF值采用非标准模式。另外SET ANSI_DEFAULTS [ON/OFF]命令也可以实现标准的切换,只是这个命令控制的是一组符合SQL-92标准的设置,其中就包括Null值的标准。
  默认情况下,数据库管理程序(DB-Library)是SET ANSI_NULLS为OFF的。但是我们的大多数应用程序,都是通过ODBC或者OLEDB来访问数据库的,作为一种开放兼容的数据库访问程序,或许是兼容性的考虑,SET ANSI_NULLS值设置为ON。这样一来带来的一些问题是需要注意的。像存储过程或者自定义函数这样的应用程序都是基于DB-Library的,默认情况下,SET ANSI_NULLS为OFF,并且在这样的程序中,不能使用SET ANSI_NULLS在一个环境中修改规则,只能修改数据库配置参数。
  考虑下面这种情况。
你的应用程序使用ADODB来访问数据库,采用OleDb或者ODBC数据提供程序。对于前面的查询1:
select * from T where Data=null
你可以直接发送命令取得结果集,也可以把它放到存储过程当中。但是他们的查询结果是不一样的。如果直接使用查询命令,什么结果也没有,而如果访问存储过程,你获得第2行的数据。
  我写了一个.Net程序来验证这一点。同时也为了验证.Net SqlClient的SET ANSI_NULLS的设置,由于SqlClient不是通过OleDb或者ODBC这些数据提供程序来访问SQL Server,而是直接对SQL Server进行访问,本来我以为它会采用SQL Server默认的设置,但是结果恰恰相反,它的默认设置和OleDb、ODBC一样。
  using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Data.Odbc;
public class AnsiNullsTest{
public static void Main(String[] args){
   IDbConnection conn;
   String connType = "SqlClient";
  if(args.Length>0)connType = args[0];
  if(connType.ToUpper()=="OLEDB"){
    Console.WriteLine("Connection Type:OLEDB");
    conn = new OleDbConnection("Provider=SQLOLEDB.1;User ID=sa;PWD=test;Initial Catalog=TEST;Data Source=TEST");
   }else if(connType.ToUpper()=="ODBC"){
    Console.WriteLine("Connection Type:ODBC");
    conn = new OdbcConnection("Driver={SQL Server};UID=sa;PWD=test;Database=TEST;Server=TEST");
   }else{
    Console.WriteLine("Connection Type:SQLClient");
    conn = new SqlConnection("Server=TEST;Database=TEST;User ID=sa;PWD=test");
   }
   Test(conn);
}
public static void Test(IDbConnection conn){
   String query1 = "select 'Test' where null=null";
   String query2 = "exec p_Test"; //存储过程中是一样的SQL语句
   IDbCommand cmd;
   IDataReader reader;
   Console.WriteLine("print 'Test' set ansi_nulls off");
  try{
    cmd = conn.CreateCommand();
    conn.Open();
    cmd.CommandText = query1;
    reader = cmd.ExecuteReader();
    Console.WriteLine("command:" + query1);
   while(reader.Read()){
     Console.WriteLine("result:" + reader[0].ToString());
    }
    reader.Close();
    cmd.CommandText = query2;
    reader = cmd.ExecuteReader();
    Console.WriteLine("command:" + query2);
   while(reader.Read()){
     Console.WriteLine("result:" + reader[0].ToString());
    }
    reader.Close();
   }
  catch(Exception ex){
    Console.WriteLine(ex.Message);
   }
  finally{
    conn.Close();
   }
  
}
}
  它有一个参数,根据参数采用不同的参数值采用不同的数据库访问程序。命令对象作了两次查询,一次是SQL查询命令,一次是调用存储过程。语句都是一样,但是结果不一样。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-82158-1-1.html 上篇帖子: SQL Server 2005数据挖掘模型算法 下篇帖子: SQL Server 性能调优(io)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表