设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

返回列表 发新帖
查看: 2373|回复: 2

[查询] “见空之时,见非是空”——浅谈在模糊查询中使用null

[复制链接]
发表于 2018-8-31 12:08:15 | 显示全部楼层 |阅读模式
      前几天,版友wuhongzhou在我回复的帖子上提出了一个疑问,使用刘小军常用窗体查询(没学过?点击这里)的方法创建查询时,如果查询字段有空值,使用下面的语句,为什么会查不到?
Like IIf(IsNull([Forms]![存书查询窗体]![书名]),'*','*'& [Forms]![存书查询窗体]![书名]& '*')
      其实,原先的Word说明文档里已经提及了这一点。只不过可能很多人和我当时那样蜻蜓点水一般掠过,不会留意到罢了:
当我们在窗体“存书查询窗体”上面的“书名”里什么也没有写,整个式子的结果是:
LIKE *
相当于查询所有的有书名的书。
     
      回到前面的问题,其实我们更应该关注的是:为什么查询条件的字段里存在空值。我们知道,设计查询时,并没有规定不能使用空值。但从使用场景来看,如果允许空值,将面临一个很费解的问题:
      当你什么都没输入的时候,电脑该如何理解你的需求:是想查全部数据,还是想查空值的数据

      我们先来看如何理解查询空值:
      《楞严经》云:“见空之时,见非是空”。也就是说,当你见到空无的时候,所见不是空无。因为“见”至少需要2个条件。一是眼睛,二是光线。更何况光线的颜色同样会影响你的所见。是否为空,并不能只靠视觉来判断。例如,我们说前面什么都看不到,是空的。但实际呢?眼前有空气,也许还有尘埃,病菌……只是人眼看不到罢了。绝对意义上的空无,应该由其定义来判断,而不是人眼。

      同样地,我们查找空值,也应该由其定义来处理。因此查询时,用的:where 字段 is null。这时候,我们回头看看前面的like子句,如何整合?
      where 书名 Like IIf(IsNull([Forms]![存书查询窗体]![书名]),'*','*'& [Forms]![存书查询窗体]![书名]& '*')
      一个是字段 like ……,一个是字段 is null,显然,在SQL语句层面是无法直接处理的。——也就是说,要么使用多个查询,根据需求来调用;要么使用其它手段修改SQL语句。


      既然空值是无法直接查询得到,那么查找全部数据会怎么样呢?显然,若是继续使用“Like *”,则会过滤掉条件为NULL的记录;如需包含条件为NULL的记录,要么使用联合查询,要么删掉这个条件子句(即该字段不设置条件),换句话说,不修改条件子句将无法完成。伪代码如下:
  1. if isnull(控件) then
  2. 查询.SQL=SQL1
  3. else
  4. 查询.SQL=SQL2
  5. end if
复制代码

      理解完这一点之后,我们可以开始来写语句了:
  1. Private Sub Command0_Click()

  2.     Dim qry As DAO.QueryDef
  3.     Dim strWhere As String
  4.    
  5.     Set qry = CurrentDb.QueryDefs("更好一点的查询")
  6.    
  7.     strWhere = " Where TRUE"
  8.    
  9.     If IsNull(Me.xm) Then
  10.         strWhere = strWhere & " "
  11.     Else
  12.         strWhere = strWhere & " and  员工姓名 like '" & Me.xm & "'"
  13.     End If
  14.    
  15.     If IsNull(Me.jc) Then
  16.         strWhere = strWhere & " "
  17.     Else
  18.         strWhere = strWhere & " and 奖惩类型 like '" & Me.jc & "'"
  19.     End If
  20.     strWhere = "SELECT DISTINCTROW 基本信息.员工姓名, 基本信息.员工编号, 基本信息.部门, 基本信息.岗位, 奖惩.奖惩类型, 奖惩.奖惩原因, 培训.培训时间, 培训.培训课程" _
  21.             & " FROM (基本信息 LEFT JOIN 奖惩 ON 基本信息.员工编号 = 奖惩.员工编号) LEFT JOIN 培训 ON 基本信息.员工编号 = 培训.员工编号" & strWhere
  22.             
  23.     qry.SQL = strWhere
  24.     qry.Close
  25.    
  26.     Me.更好一点的查询.Form.RecordSource = ""
  27.     Me.更好一点的查询.Form.RecordSource = "更好一点的查询"
  28.    
  29. End Sub
复制代码
     需要注意的是,这里使用:

  1. Me.更好一点的查询.Form.RecordSource = ""
  2. Me.更好一点的查询.Form.RecordSource = "更好一点的查询"
复制代码

      来代替常用的Me.更好一点的查询.ReQuery。这是考虑到查询处理完,不会立即在窗体上呈现的。因此需要先清空窗体记录数据源,然后再加载一次,从而达到更新的效果。
      附件如下,喜欢的话,就下载看看吧。絮絮叨叨说了这么多,希望新手能够理解,并尽可能避免产生上面那个费解的问题。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

点击这里给我发消息

发表于 2018-9-2 09:16:35 | 显示全部楼层
谢谢分享!
这个问题问的人比较多
 楼主| 发表于 2018-9-3 09:23:01 | 显示全部楼层
tmtony 发表于 2018-9-2 09:16
谢谢分享!
这个问题问的人比较多

确实问得比较多,但是新手们很多也没去认真思考这个问题:当输入为空的时候,很容易让用户陷入思维混乱的地步:为什么不是查空值的记录,而是显示全部记录?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-4-18 12:24 , Processed in 0.152559 second(s), 28 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

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