使用两个别名和两个比较将 *= 正确转换为 LEFT OUTER JOIN
Converting *= to LEFT OUTER JOIN correctly with two aliases and two comparisons
我想将 *=
的 SQL 语法转换为 LEFT OUTER JOIN
。这是原始语法:
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a,
tableB AS b
WHERE
a.col1 *= b.col1 AND
a.col2 *= b.col2 AND
b.col3 = "xxx"
b.col4 = "yyy"
我正在尝试以下操作,但由于加入,returns 行太多了。我做错了什么?
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1
LEFT OUTER JOIN tableB ON a.col2 = b.col2
WHERE
b.col3 = "xxx"
b.col4 = "yyy"
您可以在 JOIN
语法中使用 AND
:
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx"
b.col4 = "yyy"
一个LEFT JOIN
就够了。你能试试这个吗
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx"
AND b.col4 = "yyy"
试试下面的示例代码
SELECT a.col1, a.col2, b.col1, b.col2, b.col3, b.col4
FROM tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx" AND b.col4 = "yyy"
您的第一个查询仅涉及 一个 两个 table 的左连接,因为涉及同一对别名的所有 *=
比较都用于一个离开加入。所以我们把它们聚集成一个 left join
的 on
.
当只剩下一对table加入from
时,非*
的一列table与常量的比较也是左连接标准的一部分。所以它也进入 on
:
In a left join, the outer table and inner table are the left and right tables
respectively.
If you submit a query with an outer join and a qualification on a column from the inner table of the outer join, the results may not be what you expect. The qualification in the query does not restrict the number of rows returned, but rather affects which rows contain the null value. For rows that do not meet the qualification, a null value appears in the inner table’s columns of those rows.
这给出:
SELECT
a.col1, a.col2, b.col1, b.col2, b.col3, b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b
ON a.col1 = b.col1 AND a.col2 = b.col2
AND b.col3 = "xxx" ??? b.col4 = "yyy"
有关完整的语义,请参阅 Transact-SQL® Users Guide for Adaptive Server® Enterprise 15.7。特别是 *
一些多连接查询的左连接语义从版本 12.0 开始发生了变化。
备注:
- 正如 philipxy 所提到的,提供 minimal, complete and verifiable example 将对解决您的问题有很大帮助;特别是我们不知道您的源数据是什么样的,您当前收到的结果,也不知道您想要生成的结果(所以像 "gives exactly the same results" 这样的评论对我们来说毫无意义,因为我们没有示例通过)
- 正如其他人所提到的,您只需要
left (outer) join
到 TableB 的一份副本(使用 2/4 on
子句 - 更多内容见下文)
- 您没有提到您使用的是哪个 Sybase RDBMS 产品,所以我假设您使用的是 Sybase ASE
出于讨论目的,我将创建几个表和一些示例数据:
use tempdb
go
if object_id('tableA') is not NULL drop table tableA
go
if object_id('tableB') is not NULL drop table tableB
go
create table tableA
(col1 int
,col2 int
)
go
insert tableA values (1,1)
insert tableA values (1,2)
insert tableA values (2,3)
insert tableA values (2,4)
go
create table tableB
(col1 int
,col2 int
,col3 varchar(10) null
,col4 varchar(10) null
)
go
insert tableB values (1,1,'xxx','yyy')
insert tableB values (1,2,null,null)
go
使用旧的外部联接编写方式(即 *=
和 =*
),所有 where
子句都在联接操作期间应用,从而得到以下结果:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA AS a,
tableB AS b
where a.col1 *= b.col1
and a.col2 *= b.col2
and b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 NULL NULL NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
虽然第一条 tableA
记录基于 a) 2 个搜索参数 (SARG) 子句 (col3=xxx, col4=yyy) 和 b) 连接子句找到匹配...其他 3 tableA
条记录未找到匹配项(主要是因为 2 个 SARG 子句没有匹配项)因此 所有 tableB
列都填充了 NULL。
我们可以使用以下 left (outer) join
样式查询生成相同的结果集:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
and b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 NULL NULL NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
同样,SARG 子句作为连接操作的一部分应用。
现在,如果 objective 在 连接操作完成后应用 SARG 子句 ,我们需要将 SARG 移动到一个单独的 where
条款;要了解这是如何工作的,我们首先 运行 仅包含连接子句的查询(即删除 SARG 子句):
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 1 2 NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
通过将 SARG 子句作为单独的 where
子句应用,我们现在可以仅过滤掉我们想要的行(即 col3=xxx 和 col4=yyy),如下所示:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
-- apply the SARGs **after** the join:
where b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
因此,在这一点上我们可以看到可以从 left (outer) join
查询样式生成几个不同的结果集...哪个结果是 'correct' 将取决于最终结果您尝试生成的结果...返回到关于提供 minimal, complete and verifiable example
的评论
我想将 *=
的 SQL 语法转换为 LEFT OUTER JOIN
。这是原始语法:
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a,
tableB AS b
WHERE
a.col1 *= b.col1 AND
a.col2 *= b.col2 AND
b.col3 = "xxx"
b.col4 = "yyy"
我正在尝试以下操作,但由于加入,returns 行太多了。我做错了什么?
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1
LEFT OUTER JOIN tableB ON a.col2 = b.col2
WHERE
b.col3 = "xxx"
b.col4 = "yyy"
您可以在 JOIN
语法中使用 AND
:
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx"
b.col4 = "yyy"
一个LEFT JOIN
就够了。你能试试这个吗
SELECT
a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx"
AND b.col4 = "yyy"
试试下面的示例代码
SELECT a.col1, a.col2, b.col1, b.col2, b.col3, b.col4
FROM tableA AS a
LEFT OUTER JOIN tableB AS b ON a.col1 = b.col1 AND a.col2 = b.col2
WHERE
b.col3 = "xxx" AND b.col4 = "yyy"
您的第一个查询仅涉及 一个 两个 table 的左连接,因为涉及同一对别名的所有 *=
比较都用于一个离开加入。所以我们把它们聚集成一个 left join
的 on
.
当只剩下一对table加入from
时,非*
的一列table与常量的比较也是左连接标准的一部分。所以它也进入 on
:
In a left join, the outer table and inner table are the left and right tables respectively.
If you submit a query with an outer join and a qualification on a column from the inner table of the outer join, the results may not be what you expect. The qualification in the query does not restrict the number of rows returned, but rather affects which rows contain the null value. For rows that do not meet the qualification, a null value appears in the inner table’s columns of those rows.
这给出:
SELECT
a.col1, a.col2, b.col1, b.col2, b.col3, b.col4
FROM
tableA AS a
LEFT OUTER JOIN tableB AS b
ON a.col1 = b.col1 AND a.col2 = b.col2
AND b.col3 = "xxx" ??? b.col4 = "yyy"
有关完整的语义,请参阅 Transact-SQL® Users Guide for Adaptive Server® Enterprise 15.7。特别是 *
一些多连接查询的左连接语义从版本 12.0 开始发生了变化。
备注:
- 正如 philipxy 所提到的,提供 minimal, complete and verifiable example 将对解决您的问题有很大帮助;特别是我们不知道您的源数据是什么样的,您当前收到的结果,也不知道您想要生成的结果(所以像 "gives exactly the same results" 这样的评论对我们来说毫无意义,因为我们没有示例通过)
- 正如其他人所提到的,您只需要
left (outer) join
到 TableB 的一份副本(使用 2/4on
子句 - 更多内容见下文) - 您没有提到您使用的是哪个 Sybase RDBMS 产品,所以我假设您使用的是 Sybase ASE
出于讨论目的,我将创建几个表和一些示例数据:
use tempdb
go
if object_id('tableA') is not NULL drop table tableA
go
if object_id('tableB') is not NULL drop table tableB
go
create table tableA
(col1 int
,col2 int
)
go
insert tableA values (1,1)
insert tableA values (1,2)
insert tableA values (2,3)
insert tableA values (2,4)
go
create table tableB
(col1 int
,col2 int
,col3 varchar(10) null
,col4 varchar(10) null
)
go
insert tableB values (1,1,'xxx','yyy')
insert tableB values (1,2,null,null)
go
使用旧的外部联接编写方式(即 *=
和 =*
),所有 where
子句都在联接操作期间应用,从而得到以下结果:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA AS a,
tableB AS b
where a.col1 *= b.col1
and a.col2 *= b.col2
and b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 NULL NULL NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
虽然第一条 tableA
记录基于 a) 2 个搜索参数 (SARG) 子句 (col3=xxx, col4=yyy) 和 b) 连接子句找到匹配...其他 3 tableA
条记录未找到匹配项(主要是因为 2 个 SARG 子句没有匹配项)因此 所有 tableB
列都填充了 NULL。
我们可以使用以下 left (outer) join
样式查询生成相同的结果集:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
and b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 NULL NULL NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
同样,SARG 子句作为连接操作的一部分应用。
现在,如果 objective 在 连接操作完成后应用 SARG 子句 ,我们需要将 SARG 移动到一个单独的 where
条款;要了解这是如何工作的,我们首先 运行 仅包含连接子句的查询(即删除 SARG 子句):
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
1 2 1 2 NULL NULL
2 3 NULL NULL NULL NULL
2 4 NULL NULL NULL NULL
通过将 SARG 子句作为单独的 where
子句应用,我们现在可以仅过滤掉我们想要的行(即 col3=xxx 和 col4=yyy),如下所示:
select a.col1,
a.col2,
b.col1,
b.col2,
b.col3,
b.col4
from tableA as a
left
join tableB as b
on a.col1 = b.col1
and a.col2 = b.col2
-- apply the SARGs **after** the join:
where b.col3 = "xxx"
and b.col4 = "yyy"
go
col1 col2 col1 col2 col3 col4
----------- ----------- ----------- ----------- ---------- ----------
1 1 1 1 xxx yyy
因此,在这一点上我们可以看到可以从 left (outer) join
查询样式生成几个不同的结果集...哪个结果是 'correct' 将取决于最终结果您尝试生成的结果...返回到关于提供 minimal, complete and verifiable example