字体
第(2/6)页
关灯
   存书签 书架管理 返回目录
“看似正确”地执行——无可否

    认,较旧的SQL语法在此方面问题较大,但ANSI/SQL92 在通过多个字段进行表的连接时也可

    能出现问题。发现重复数据容易,但发现数据不准确很难,所以避免在最高层使用distinct应该

    是一条基本规则。

    发现结果不正确更难,这很容易证明。前面使用distinct 返回客户名的两个查询,都可能返回

    不正确结果。例如,如果恰巧有多位客户都叫“Wayne”,distinct不但会剔除由同个客户的多张

    订单产生的重复项目,也会剔除由名字相同的不同客户产生的重复项目。事实上,应该同时返

    回具唯一xìng的客户ID和客户名,以保证得到蝙蝠车买家的完整清单。在实际中,发现这个问题

    可不容易。

    要摆脱distinct,可考虑以下思路:客户在Gohtam市,而且满足存在xìng测试,即在最近六个

    月订购过蝙蝠车。注意,多数(但非全部) SQL 方言支持以下语法:

    上例的存在xìng测试,同一个名字可能出现多次,但每个客户只出现一次,不管他有多少订单。

    有人认为我对ANSI SQL 语法的挑剔有点苛刻(指“蝙蝠车买主”的例子),因为上面代码中

    custcomrs表的地位并没有降低。其实,关键区别在于,新查询中custcomrs表是查询结果的唯

    一来源(嵌套的子查询会负责找出客户子集),而先前的查询却用了join。

    这个嵌套的子查询与外层的select关系十分密切。如代码第11 行所示(粗体部分),子查询

    参照了外层查询的当前记录,因此,内层子查询就是所谓的关联子查询(correlated subquery)。

    此类子查询有个弱点,它无法在确定当前客户之前执行。如果优化器不改写此查询,就必须先

    找出每个客户,然后逐一检查是否满足存在xìng测试,当来自Gotham市的客户非常少时执行效率

    倒是很高,否则情况会很糟(此时,优秀的优化器应尝试其他执行查询的方式)。

    我们还可以这样编写查询:

    select c.custncom

    from custcomrs c

    where c.city = 'GOTHAM'

    and exists (select null

    from orders o,

    orderdetail od,

    articles a

    where a.artncom = 'BATMOBILE'

    and a.artid = od.artid

    and od.ordid = o.ordid

    and o.custid = c.custid

    and o.ordered >= scomfunc )

    在这个例子中,内层查询不再依赖外层查询,它已变成了非关联子查询(uncorrelated

    subquery),只须执行一次。很显然,这段代码采用了原有的执行流程。在本节的前一个例子中,

    必须先搜寻符合地点条件的客户(如均来自GOTHAM),接着依次检查各个订单。而现在,订

    购了蝙蝠车的客户,可以通过内层查询获得。

    不过,如果更仔细地分析一下,前后两
上一页 目录 下一页