同系列的第七篇,上一篇在:
多重条件搜索
前文再续,书接上一回。很高兴又能说出这句话了。
第五章讲述了条件查询。事实上SQL:Select语句的Where子句并不只是能接受一个条件。举个实际应用的栗(例)子,如果有重名,那么按姓名去查询,就会出现多个结果,为了唯一确定一个人,我们还可以再提供需要查询的人的手机号码,一般而言这样就唯一确定一个人了。
为此,我们在数据库添加一个手机号码字段。打开数据库,然后在表的【设计视图】中,再添加一个字段,命名为【PhoneNo】。由于手机号码也有11位的长度,所以还是设置数据类型为【双精度型】,如下图所示。
然后回到【数据表视图】(在【设计视图】和【数据表视图】之间切换有更快捷的方法。就是在字段名称上面的那个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)。在【创建】菜单单击【查询设计】,如下图所示。
弹出来的一个对话框直接关掉,然后单击一下界面左上角的SQL,就可以将查询切换到【SQL视图】
将上面的SQL语句复制粘贴进去。注意,单引号要手工改一下,改成英文半角的单引号。文章这里我虽然是用英文半角输入,但是最后显示的还是中文的单引号。中文符号是不行的!!
然后单击左上角的运行之后结果就出来了,如下图所示。
观察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
加上括号之后的结果是这样的,如下图所示。没错,全部都出来了。你能想明白为什么吗?
这也是一个需要注意的问题,在布尔代数(数学)中,这样的结果称为德摩根定理:
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来显示电话号码,修改好的界面如下所示。
由于目前我用来用去都是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)
那么长时间不写教程,开始的时候还真找不到感觉,不知道自己要说什么,怎么说,真是惭愧。感觉到后面才渐渐回来了。才发现原来多重条件查询自己能说出那么多东西,于是把第五章最后修改了一下,这一章标题也修改了一下,只说多重条件查询。模糊查询和基于范围的查询之后再讲。
下一章,我将来讲述模糊搜索与基于范围的搜索,敬请期待。本套教程未完,待续。