SQL中的空值探讨

时间:2022-09-09 06:37:52

摘要:文章介绍了空值的语义和三值逻辑,并在此基础上分析了SQL语言处理空值时存在的问题并对其进行修改,构造了针对不完全信息数据库的查询语言。

关键词:空值;三值逻辑;结构化查询语言

中图分类号:TP311文献标识码:A 文章编号:1009-3044(2008)26-1629-04

1 引言

在现实世界中,信息是经常不完全的,比如:“当前地址不详”、“待宣布的发言人”、“不知道生日”等等,对此大家都已习以为常。因此,在数据库系统里很需要某些方法处理这样的不完全信息问题。这个问题的解决方法是基于空值(NULL)和三值逻辑(3VL),并很普遍地运用于实际系统中。本文对空值进行了介绍并在此基础上分析了SQL语言处理空值时存在的问题并对其进行修改。

2 空值的介绍

2.1 空值的语义

在数据库中,空值常常具有不同的语义,根据空值的语义信息,可把空值分为三类:第一种表示应该有而实际上遗漏的值,称为“存在型空值”;第二种用来表示因为不适用而根本没有该值,称为“不存在型空值”;第三种是尚不知道是否存在该值,称为“占位型空值”。SQL标准中把空值定义为一个用来表示缺失数据值的特殊值或者标记,它不属于域中的一个值,而是系统中的一个特殊标志,表示属性值是“未知的”。SQL语言对空值的语义限制较多,用单个NULL表示存在型和不存在型两种空值,而占位型空值无法表示。SQL语言的真实语义是基于三值逻辑的,对一个条件表达式求值有三种结果:真、假和未知。

2.2 NULL与三值逻辑

在无空值的环境下,比较运算的结果有两个可能的逻辑值:true或false,这种逻辑称为二值逻辑。空值引入后,二值逻辑就不能适应空值环境了,比较运算可能有三种结果:true,false或unknown,称为三值逻辑,三值逻辑真值表见表1。

尽管我们经常把NULL和Unknown互换使用,但从技术角度来讲,两者并不一样,NULL是一个数据的值,而Unknown表示一个逻辑值。

2.3 NULL值的处理

1) 引入空值后为了保护数据的完整性,SQL中加入了NOT NULL约束条件来约定某一列的属性值不能为空。

若没有使用NOT NULL或用NULL实施约束,则该列可以取NULL值。如下列语句定义表STUDENT并在SNAME列上指定NOT NULL约束:

CREATE TABLE STUDENT(

SNO CHAR(8) PRIMARYKEY,

SNAME VARCHAR(10) NOT NULL,

HEIGHT NUMERIC(6,2));

2) 在SQL的SELECT、INSERT、UPDATE、DELETE等语句的WHERE子句中,可以使用IS NULL。

判断一个值是否为NULL,或IS NOT NULL判断一个值是否不为NULL构成条件,如:

SELECT*

FROM SCORE

WHERE GRADE IS NULL;

这里由于NULL不是值,所以涉及NULL的比较条件不得使用=或!=比较符号,而只能使用IS NULL或IS NOT NULL。

3) 用INSERT语句向关系中插入元组时,若没有给出全部列的值,则没有给出值的列自动默认值以NULL 填充,当然那些列在定义时应允许为NULL且没有指定默认值。

4) 在SELECT语句中,若含有ORDER BY排序子句,若排序的列含有NULL值,则NULL被认为最大,即若排序为升序,含有NULL值的元组被排在最后,反之被排在前面输出。如语句:

SELECT*

FROMSCORE

ORDER BYGRADE DESC;

将GRADE列值为NULL的元组首先输出。

5) 在使用UPDATE语句更新某列值为NULL时,需要在SET子句中用SET〈列名〉=NULL,如:

UPDATESCORE

SETGRADE=NULL

WHERESNO='9900010'

ANDCNO='C101';

6) 在进行关系的外连接运算时,用NULL值填充不符合连接条件的另一表中对应属性列的值。如:

CREATE VIEW S_C

AS SELECT STUDENT.SNO, SNAME, CNO, GRADE

FROM STUDENT, SCORE

WHERE STUDENT.SNO=SCORE.SNO(+);

则在S_C视图中,没有选课的学生的课号(CNO)和成绩(GRADE)的值均为NULL。

7) NULL在函数中的使用,在所有的标量(scalar)函数中(除NVL和TRANSLATE外),当参数为NULL时,结果均返回NULL。在NVL(expression1,

expression2)函数中,若expression1结果为NULL,则返回expression2的值,否则返回expression1的值。

在使用聚集函数进行分组查询的SELECT语句中,AVG( )、SUM( )、MAX( )及MIN( )的函数忽略NULL值,例如,某查询求五个值80、NULL、NULL、NULL和90的平均值,计算结果为(80+90)/2=85。

SELECT AVG(GRADE)

FROM SCORE

WHERE SNO='99000101'

GROUP BY SNO;

而COUNT( )函数则包含所有的元组,即

SELECT COUNT (GRADE)

FROM SCORE

GROUP BY GRADE;

上述结果为5。

3 SQL查询的修改

3.1 SQL处理空值存在的问题

SQL语言语义基于集合论和三值逻辑,是二者的结合。集合论是和二值逻辑统一的,而同时SQL又使用三值逻辑,因此SQL对不完全信息数据库的处理结果可能并不是用户所期望的,不能保证结果的完备性。SQL语言处理查询的非程序化使其表达比较简单,但是对于不完全信息数据库,使用SQL语言进行查询求解时,不得不将三值逻辑转化为二值逻辑,其结果可能并不符合用户的要求,不能代表数据库的确切信息,这样得到的结果就会和查询求解下的封闭世界假设产生矛盾。所谓封闭世界假设是针对基于不含空值的完备关系数据库而言的,即在对数据库进行查询求解时假设数据库中只含有确定和完备的信息,对数据库中没有包含的信息都认为是假。对一个含有空值的数据库进行查询操作时,SELECT语句中的WHERE子句需要使用三值逻辑对条件进行判断。由于SQL语言规定只有当元组的值使得条件为真时才满足查询要求,因此此规定就隐含着进行了从三值逻辑向二值逻辑的强制性转化。在这种情况下,若同时使用否定词NOT和全称量词ALL,就会出现严重的信息丢失。例如,对于以下的查询表达式:

SELECT*

FROM student

WHERE student.grade>90;

如果student表中有一个元组的grade属性值为NULL,则NULL和90进行比较,其结果是Unknown,SQL查询将Unknown转化为False,因此这个元组就不会出现在上述表达式的结果里。但现实世界中,NULL值有可能是大于90的一个数,这就造成了查询结果与用户期望值之间的矛盾。

3.2 MAYBE操作符的引入

对关系数据库进行查询,由于空值的存在,使得数据库查询结果和用户的直觉不一样,查询结果划分成3个不相交的集合。

例如对数据库表2进行以下的查询:

1) 查询成绩大于90的学生名单,SQL语句如下:

SELECT*

FROM student1

WHERE student1.grade>90;

结果为第二个元组,不包括成绩为NULL的元组;

2) 查询成绩不大于90的学生名单,SQL语句如下:

SELECT*

FROM student1

WHERE NOT(student1.grade>90)

结果为第一个元组,不包括成绩为NULL的元组;

从示例可见,对于元组中成绩属性含有NULL的数据库,上述两个查询并不能包括整个数据库,因此,查询结果就将数据库划分为三个不相交的集合。而对于完全信息数据库,这两个查询可以包括整个数据库表。为了能够表示得到含有空值的元组的查询,我们引入了MAYBE操作符,它是和NOT操作符类似的一元操作符。凡是SQL语言中可以出现NOT的地方都可用MAYBE替换,例如MAYBEIN、MAYBE BETWEEN、MAYBE LIKE和MAYBE EXISTS等。在MFM系统中,联结词μ对应MAYBE操作符,同时联结词∧、∨和‘分别对应于AND、OR和NOT操作符。MAYBE的真值表为:

从表中可知,只有当表达式A的真值为Unknown时,MAYBE(A)才为True,从而可以把满足表达式A中的属性值为NULL的元组查询出来。

SQL语言中引入的MAYBE操作符,其查询语句的格式为:

SELECT<目标列表达式>

FROM<表名或视图名>

WHERE MAYBE<条件表达式>

对于单条件表达式的MAYBE操作符的语法格式,由于其处理的特殊性,可以把表达式简写为属性列名,所得结果是相同的。

例如对于查询成绩可能等于90的学生名单,其SQL查询语句如下:

SELECT*

FROM student1

WHERE MAYBE(student1.grade=90);

可以简化为:

SELECT*

FROM student1

WHERE MAYBE(student1.grade);

这个查询的结果就是表3的第三个元组。因为其grade属性值为NULL,所以student1.grade的真值就是Unknown,从而MAYBE(student1.grade)的真值为T,满足WHERE查询条件。

MAYBE的语义规则:MAYBE可以在一个谓词表达式前使用,或者以MAYBEIN的形式出现。对于MAYBE IN谓词,其格式为<row value consturctor>MAYBEIN<in predicate value>。

3.3 SQL查询的修改

对于含有空值的数据库,在描述SQL语言时需要根据查询要求以及数据库的特点来尽量正确书写SQL查询。例如针对数据库表4所做的查询:

查询2.1查找不存在年龄和地址相同,性别不同的所有学生名单。

SQL语句如下:

SELECT*

FROM student2 x

WHERE NOT EXISTS

(SELECT *

FROM student2 y

WHERE x.Age=y.Age

AND x.Sex<>y.Sex

AND x.Address=y.Adress);

由SQL的定义可知,答案为整个数据库表。但若第二个元组的Age属性值NULL为18,则结果并不能正确反映实际情况。

查询表4查找确定不存在年龄和地址相同,性别不同的所有学生名单。SQL语句如下:

SELECT*

FROM student2 x

WHERE x.Age<>ALL

(SELECT y.Age

FROM student2 y

WHERE x.Sex<>y.Sex

AND x.Address=y.Adress);

由SQL的定义可知,答案为空。那么这个答案和查询的要求是一致的。

如上述例子所示,为了能够合理地处理不完全信息数据库的SQL查询,本文将结果分为两种类型:一种是确定信息,一种是可能信息。其中确定信息指的是肯定能够满足SQL查询条件的元组集合,可能信息指的是能够满足SQL查询条件的元组以及可能满足SQL查询条件的元组的集合,因此查询所得到的确定信息的集合是可能信息集合的子集。

例如对于数据库表2,要查找成绩大于90的学生名单。那么我们可以根据两种情况来描述SQL查询,一种是为了得到成绩肯定大于90的学生名单,即确定信息,SQL查询如下:

SELECT*

FROM student1

WHERE student1.grade>90;

这种情况下,SQL的语义和传统的SQL语义相同,同样是将三值逻辑转化为二值逻辑,即把使得查询条件为Unknown的元组转化为查询条件为False的元组。此查询的结果为第二个元组。

对于确定信息,同样需要引入MAYBE操作符。在这种情况下,SQL查询的结果分为三个不相交的集合,即查询条件为真的行,查询条件为假的行和查询条件为未知的行,对应的SQL语句分别为:

SELECT*FROM……WHERE<条件>

SELECT*FROM……WHERE NOT<条件>

SELECT*FROM……WHERE MAYBE<条件>

第二种是为了找到那些成绩可能大于90的学生名单,即可能信息,SQL查询如下:

SELECT*

FROM student1

WHERE student1.grade>90 OR MAYBE(student1.grade>90);

此查询的结果为第二个和第三个元组。

经过对SQL查询的修改,WHERE搜索条件的真值只有两种取值:True和False。若元组满足第一个搜索条件,则整个WHERE搜索条件为T;若元组不满足第一个搜索条件,则整个WHERE搜索条件为F;若元组使得第一个搜索条件为Unknown,则会使得第二个搜索条件为T,因此整个WHERE搜索条件为T。所以,这个查询就不存在将WHERE条件由三值逻辑强制转化为二值逻辑的情况,从而保证了SQL语义的完备性。

在这种情况下,因为要得到的结果为可能信息,因此SQL查询只有一种语法格式,即:

SELECT*FROM……WHERE<条件>OR MAYBE<条件>

4 总结

在几乎所有的DBMS中都涉及到NULL值的使用规定,但不同的DBMS对NULL值的使用规定又各不相同。在我们开发数据库应用程序时应该准确了解有关DBMS对NULL值的使用规定,本文在对SQL语言处理不完全信息所存在的问题进行分析的基础上,引入了新的操作符MAYBE,并对SQL查询进行了修改,使其能较好地处理空值。

参考文献:

[1] 潘娜.不完全信息系统的理论研究[D].南京:南京航空航天大学,2005.

[2] 郝忠孝,胡春海.空值环境下关系数据库查询处理方法[J].计算机学报,1994,17(3):218-222.

[3] 马宗民.空值环境下含不确定及可能信息关系数据库的更新[J].计算机研究与发展,1996,33(1):39-46.

[4] 马宗民,严丽.含有空值关系数据库的查询处理[J].计算机研究与发展,1995,32(9):31-36.

上一篇:齿轮参数化绘图设计 下一篇:浅析基于Lucene框架的网络论坛信息分析与实现