同系列的第七篇,上一篇在:


多重条件搜索


前文再续,书接上一回。很高兴又能说出这句话了。

第五章讲述了条件查询。事实上SQL:Select语句的Where子句并不只是能接受一个条件。举个实际应用的栗(例)子,如果有重名,那么按姓名去查询,就会出现多个结果,为了唯一确定一个人,我们还可以再提供需要查询的人的手机号码,一般而言这样就唯一确定一个人了。

为此,我们在数据库添加一个手机号码字段。打开数据库,然后在表的【设计视图】中,再添加一个字段,命名为【PhoneNo】。由于手机号码也有11位的长度,所以还是设置数据类型为【双精度型】,如下图所示。


access dlookup 多条件_VB



然后回到【数据表视图】(在【设计视图】和【数据表视图】之间切换有更快捷的方法。就是在字段名称上面的那个Student那里,单击鼠标右键,最下面会有选择进入什么视图)。手工修改一下数据。修改好的数据如下所示:

 StudentID 

 StudentName 

 PhoneNo

 123456

 林则徐

 13888080088 

 562893

 叶剑英

 13920171101

 662356

 黄飞鸿

 13427103456

 785714

 黄飞鸿

 13978569013

电话号码都是随便乱编的。不过可以看到,有两个“黄飞鸿”,不过学号和电话都不一样。这样只按第五章所说的,给出条件WHERE StudentName=’黄飞鸿’去查询,结果就会有两个了。


为了继续讲下去,还是必须要先讲一下逻辑连接词。什么是逻辑连接词呢?我们经常会这样说话:“姓名是黄飞鸿,而且电话号码是13978569013 的人”,这里姓名和电话号码是两个条件,用“而且”两个字连接起来,“而且”就是逻辑连接词。

在SQL中,使用“与”(AND),“或”(OR),“非”(NOT)三个逻辑连接词来连接多个条件。前面的“而且”相当于是“与”(AND)。

例如“姓名是黄飞鸿,而且电话号码是13978569013 的人”,SQL语句可以写成:

SELECT * FROM Student WHERE StudentName=’黄飞鸿’ AND PhoneNo=13978569013

 

逻辑连接词的结合性

WHERE后面不仅能接两个条件,还可以接多个条件,而且逻辑连接词也不要求整一个语句都是用同一个连接词。但是,如果有多个不同的连接词,如何理解就会出现问题。例如:

SELECT * FROM Student WHERE StudentName=’黄飞鸿’ AND PhoneNo=13978569013 OR PhoneNo=13888080088

为了突出一些,我让每个条件显示成不同的颜色。这条语句的条件翻译成中文是这样说的“学生名是黄飞鸿,且电话号码是13978569013,或电话号码是13888080088”。这样问题来了,这句话可以有两种理解:

1.      (学生名是黄飞鸿,且电话号码是13978569013),或者是电话号码是13888080088的任何一个人【不论名字】

2.      学生名是黄飞鸿,(且电话号码是13978569013,或者是电话号码是13888080088)【姓名一定要黄飞鸿,电话是这两个之一就行,有其他的不要】

 

为了检验我们的理解那一种是正确的。启动Access(图示的版本是2013)。在【创建】菜单单击【查询设计】,如下图所示。


access dlookup 多条件_access dlookup 多条件_02



弹出来的一个对话框直接关掉,然后单击一下界面左上角的SQL,就可以将查询切换到【SQL视图】


access dlookup 多条件_VB_03



将上面的SQL语句复制粘贴进去。注意,单引号要手工改一下,改成英文半角的单引号。文章这里我虽然是用英文半角输入,但是最后显示的还是中文的单引号。中文符号是不行的!!


access dlookup 多条件_VB_04



然后单击左上角的运行之后结果就出来了,如下图所示。


access dlookup 多条件_数据库_05



观察Student表的数据可以知道,电话号码是13888080088的人名叫林则徐。而查询的结果中也包含了林则徐。这就证明第一种理解是正确。由此我们可以得出结论:

SQL中的多个逻辑连接词总是从左往右运算的(左结合性)。

所以(StudentName=’黄飞鸿’ AND PhoneNo=13978569013)构成一个整体,然后再附加一个OR PhoneNo =13888080088。前面的给出了唯一的结果,即上图的第二条记录。然后PhoneNo =13888080088确定了第一条,名字是林则徐的记录。

而且需要注意的是,结果记录集的排序与查询的条件无关。以后我会讲到按照某个字段的升序或降序进行排序。同样也是在SQL:Select中完成的。

在SQL语句中,括号可以改变运算的顺序,如果你真的要SQL是按照第二种理解执行的话,可以加上括号(英文半角括号):

SELECT * FROM Student WHERE StudentName=’黄飞鸿’ AND (PhoneNo=13978569013 ORPhoneNo=13888080088)

运行的结果只有一条,就是上图中的第二条记录。

 

“非”(NOT)逻辑连接词

这个逻辑连接词出现的频率极高。他可以搭配其他的逻辑连接词使用,而且只对出现在其右边的一个条件起作用。例如:

SELECT * FROM Student WHERE NOT

本来“非“(NOT)逻辑连接词的加入,也会使语句在人理解的时候出现歧义,但是经过实验,NOT只对右边的一个条件起作用。实验的方式也是跟上面一样的,在Access里运行一下语句看看结果即可。也就是说,上面这条语句的条件是“姓名不是黄飞鸿,并且电话号码是13888080088的人”。所以这条语句的结果就是上图的第一条记录,林则徐的那条,因为13888080088是林则徐的电话号码,而且姓名“林则徐”也满足“姓名不是黄飞鸿”的条件。

同样的,如果你希望让NOT作用与多个条件,就要加上括号:

SELECT * FROM Student WHERE NOT

加上括号之后的结果是这样的,如下图所示。没错,全部都出来了。你能想明白为什么吗?


access dlookup 多条件_数据库_06



这也是一个需要注意的问题,在布尔代数(数学)中,这样的结果称为德摩根定理:

1.      NOT( a AND b)      等价于  (NOT a) OR(NOT b)

2.      NOT( a OR b)        等价于  (NOT a) AND (NOT b)

这两条结论称为德摩根定理。其中的a,b可以是任意的条件。根据德摩根定理,上面的结果就很容易理解了

NOT

等价于

(NOT StudentName='黄飞鸿') OR (NOT

名字不是黄飞鸿的有林则徐,叶剑英。电话号码不是13888080088(对应名字是林则徐)的有两个黄飞鸿,还有叶剑英。中间用OR连接,那当然是全都出来了。其实直接理解也是可以的,名字是黄飞鸿,电话号码是13888080088的人是没有的,所以结果是空的,最后NOT一下,空的相反就是全部了。

所以,如果要给NOT加括号,那就要想清楚了。

接着,我们来写一下代码检查一下,界面当然是要修改一下的,增加一个ListBox来显示电话号码,修改好的界面如下所示。


access dlookup 多条件_Access_07


由于目前我用来用去都是SQL:Select语句,所以我不说,大家也应该知道怎么做了吧。新的测试只需要将RecordSet对象的Open方法的第一个参数换成相应的SQL语句即可。不过因为改变了界面,所以我还是贴出全部的代码以供参考。这份代码只检验了语句SELECT* FROM Student WHERE StudentName=’黄飞鸿’ AND PhoneNo=13978569013 OR PhoneNo =13888080088的结果。

VB代码开始:

Dim Cnn As ADODB.Connection

Dim rec As ADODB.Recordset

Private Sub Form_Load()

        '创建新的Connection对象

        Set Cnn= New ADODB.Connection

        '注意要记住该数据库目录为你数据库文件当前的位置

        Cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\Sample.mdb;PersistSecurity Info=False"

        '创建新的Recordset对象

        Set rec= New ADODB.Recordset

        '打开student表的全部字段的全部内容


'adOpenKeyset, adLockOptimistic。键集游标和开放式锁。

'单纯为了读取数据应该使用只进游标和只读锁。

'但是为了方便就统一使用键集游标和开放式锁了

'详细参见第十章

        rec.Open "SELECT * FROM Student WHERE StudentName='黄飞鸿' AND PhoneNo=13978569013 OR  PhoneNo =13888080088", Cnn, adOpenKeyset, adLockOptimistic


        '数据的提取

        Do Until rec.EOF = True

                List1.AddItem rec.Fields("StudentID").Value

                'Fields对象,括号里的是索引(Index),索引填写的内容为字段的名称

                'Item属性是Fields对象的默认属性,他的一个参数就是Index

                'Fields("Student")表示一个Field对象

                'Fields("Student")等价于

                'rec.Fields.Item("Student")或

                'rec.Fields!("Student")

                '!表示默认属性


                List2.AddItem rec.Fields("StudentName").Value

                List3.AddItem rec.Fields("PhoneNo").Value

                '移动下一条记录为当前记录

                rec.MoveNext

        Loop

End Sub

VB代码结束

在这里罗列出这一章所给出的SQL语句,读者自己把它们放到Open方法的第一个参数中,运行一下程序,结果跟上面再Access中执行SQL的结果是一样的,就不再截图了。

本章相关的SQL语句:

1.      SELECT * FROM Student WHERE StudentName=’黄飞鸿’ AND PhoneNo=13978569013 OR PhoneNo =13888080088

2.      SELECT * FROM Student WHERE StudentName=’黄飞鸿’ AND (PhoneNo=13978569013 OR PhoneNo =13888080088)

3.      SELECT * FROM Student WHERE NOT StudentName='黄飞鸿' AND PhoneNo=13888080088

4.      SELECT * FROM Student WHERE NOT (StudentName='黄飞鸿' AND PhoneNo=13888080088)

 

那么长时间不写教程,开始的时候还真找不到感觉,不知道自己要说什么,怎么说,真是惭愧。感觉到后面才渐渐回来了。才发现原来多重条件查询自己能说出那么多东西,于是把第五章最后修改了一下,这一章标题也修改了一下,只说多重条件查询。模糊查询和基于范围的查询之后再讲。

下一章,我将来讲述模糊搜索与基于范围的搜索,敬请期待。本套教程未完,待续。