PG迁移必读(十三):Sybase左右连接与筛选条件组合的深入解析
Barry Chen

前言:Sybase的左右连接运算符(*=,=*)提供了一种简洁的方式来实现LEFT JOIN,RIGHT JOIN语法,但在与筛选条件组合时,其行为比较令人费解。本文将深入探讨Sybase左连接运算符(*=)与筛选条件组合时的行为,并提供一些CP8项目中遇到的实际案例。对于右连接(=*)的分析,读者可自行研究。

Sybase左连接运算符(*=)基础

在Sybase中,左连接运算符(*=)用于指定左连接。它保留了左侧表的所有行,即使右侧表中没有匹配的行。例如,以下查询将左侧表l的所有行与右侧表r中匹配的行结合起来:
SELECT l.*, r.* FROM l *= r

等价于:
SELECT l.*, r.* FROM l LEFT JOIN r ON (l.id=r.id)

其中表l和r的结构分别为:
create table r( id int, name varchar(8) ) 

create table l( id int, name varchar(8) ) 

插入以下测试数据,执行左连接后,结果如下图所示:

insert into l values( 1, 'aaa'

insert into l values( 2, 'bbb'

insert into l values( 3, 'ccc'

insert into r values( 1, 'AAA'

insert into r values( 2, 'bbb')  

insert into r values( 4, 'DDD')

Sybase左连接(*=)与筛选条件的组合

当左连接与筛选条件组合时,需要特别注意条件的放置,因为Sybase的行为与其他数据库系统不同。

示例1:筛选右侧表的条件

考虑以下两个查询:

-- 查询1

SELECT l.*, r.* FROM l, r WHERE l.id *= r.id AND r.name='bbb'

 

-- 查询2

SELECT l.*, r.* FROM l LEFT JOIN r ON (l.id=r.id AND r.name='bbb')

这两个查询是等价的,含义是:左侧表l和右侧表r中name='bbb’对应的记录进行左连接。在这种情况下,左连接运算符(*=)与筛选条件r.name='bbb'可以合并在一个ON子句中。

查询1结果:

查询2结果(与查询1相同):

 

然而,以下查询与上述两个查询不等价:

-- 查询3

SELECT l.*, r.* FROM l LEFT JOIN r ON (l.id=r.id) WHERE r.name='bbb'

查询3首先执行左连接,然后应用筛选条件r.name='bbb'。查询3结果如下:

 

示例2:筛选左侧表的条件

Sybase中,筛选左侧表的行为与筛选右侧表行为完全不同,不能盲目照搬示例1的准则。

-- 查询4

SELECT l.*, r.* FROM l, r WHERE l.id *= r.id AND l.name='bbb'

 

-- 查询5

SELECT l.*, r.* FROM l LEFT JOIN r ON (l.id=r.id) WHERE l.name='bbb'

这两个查询是等价的。它们都表示左侧表l和右侧表r基于l.id=r.id进行左连接,并且最后过滤出l.name='bbb'的记录。在这种情况下,筛选条件l.name='bbb'可以在WHERE子句中单独使用。

 

查询4结果:

查询5结果(与查询4结果相同):

然而,以下查询与上述两个查询不等价:

-- 查询6

SELECT l.*, r.* FROM l LEFT JOIN r ON (l.id=r.id and l.name='bbb')

查询6将l.name='bbb'作为左连接的一部分条件,这意味着只有当l.id与r.id相等且l.name的值为'bbb'时,l表中的行才会与r表中的行结合。查询6结果如下:

 

结论

深入理解Sybase中左右连接运算符与筛选条件相结合的复杂行为,对于顺利且准确地将Sybase代码迁移至PG代码具有至关重要的作用。HA的Sybase存储过程大量使用左右连接,我们对其正确理解不仅能够显著提升代码的质量水平,还能极大增强开发工作的效率。