[size=medium]这几天我在看《SQL语言艺术》的电子版。
有这样一个简单的例子:不是经理的员工当中,哪五个人收入最高。“找出不是经理的员工”是其中的关系操作部分,由此获得一个有限的员工集合,然后排序。有些SQL方言通过在select语句中增加特殊子句来限制返回的记录数,很显然,排序和限制记录数都是非关系操作。其他SQL方言(这里主要是指Oracle)则采用另外的机制,即用一个名为rownum的虚拟字段(dummy column)为查询结果编号——这意味着编号工作发生在关系操作阶段。如果查询语句如下:[/size]
[size=medium]乍一看好像没问题,但输出结果却不符合要求,并没有返回不是经理的人中“收入最高的五位”,而是返回不是经理的人中“最先被查到的五位”,以收入递减序返回。他们可能恰好是“收入最低的五位”!(这是Oracle实践者都知道的陷阱,大家都中过招。)
现在分析一下上面的代码。查询的关系操作部分仅从employees表中,以完全不可知的顺序,
取出最先发现的五位非经理人员(只包含empname和salary字段)。别忘了关系理论指出,关系
(以及描述关系的表)是无序的,关系中的元组(即记录)可以被存储或检索。上面的查询执
行后,收入最高的非经理人员或许在查询结果中,或许不在,无从知道查询结果是否满足查询
条件。正确的操作是:找出所有的非经理人员,以收入递减排序,然后返回前五条记录。代码如下:[/size]
[size=medium]看来,有些看似关系的概念其实并不属于关系操作的范畴,因为关系操作必须要有关系操作符
的参与。上面的子查询用了order by为结果集排序,而一旦用了排序操作,该数据集就已经不
是关系了(关系是无序的)。于是外层的select看似关系操作,但其实是对一个内嵌视图的结果集进行操作,其中的order by子句早已不是关系操作了。[/size]
有这样一个简单的例子:不是经理的员工当中,哪五个人收入最高。“找出不是经理的员工”是其中的关系操作部分,由此获得一个有限的员工集合,然后排序。有些SQL方言通过在select语句中增加特殊子句来限制返回的记录数,很显然,排序和限制记录数都是非关系操作。其他SQL方言(这里主要是指Oracle)则采用另外的机制,即用一个名为rownum的虚拟字段(dummy column)为查询结果编号——这意味着编号工作发生在关系操作阶段。如果查询语句如下:[/size]
select empname,salary from employees
where status != 'EXECUTIVE'
and rownum <= 5
order by salary desc
[size=medium]乍一看好像没问题,但输出结果却不符合要求,并没有返回不是经理的人中“收入最高的五位”,而是返回不是经理的人中“最先被查到的五位”,以收入递减序返回。他们可能恰好是“收入最低的五位”!(这是Oracle实践者都知道的陷阱,大家都中过招。)
现在分析一下上面的代码。查询的关系操作部分仅从employees表中,以完全不可知的顺序,
取出最先发现的五位非经理人员(只包含empname和salary字段)。别忘了关系理论指出,关系
(以及描述关系的表)是无序的,关系中的元组(即记录)可以被存储或检索。上面的查询执
行后,收入最高的非经理人员或许在查询结果中,或许不在,无从知道查询结果是否满足查询
条件。正确的操作是:找出所有的非经理人员,以收入递减排序,然后返回前五条记录。代码如下:[/size]
select * from (
select empname,salary from employees
where status != 'EXECUTIVE'
order by salary desc )
where rownum <= 5
[size=medium]看来,有些看似关系的概念其实并不属于关系操作的范畴,因为关系操作必须要有关系操作符
的参与。上面的子查询用了order by为结果集排序,而一旦用了排序操作,该数据集就已经不
是关系了(关系是无序的)。于是外层的select看似关系操作,但其实是对一个内嵌视图的结果集进行操作,其中的order by子句早已不是关系操作了。[/size]