我的同事是ANSI连接语法的新手,他最近写了一个这样的查询:
SELECT count(*)
FROM table1 t1
JOIN table2 t2 ON
(t1.col_a = t2.col_a)
JOIN table3 t3 ON
(t2.col_b = t3.col_b)
JOIN table3 t3 ON
(t3.col_c = t1.col_c);
请注意,table3在不同的列上联接到table1和table2,但这两个JOIN子句对table3使用相同的表别名。
查询运行,但我不确定它的有效性。这是编写此查询的有效方法吗?
我认为连接应该是这样的:
SELECT count(*)
FROM table1 t1
JOIN table2 t2 ON
(t1.col_a = t2.col_a)
JOIN table3 t3 ON
(t2.col_b = t3.col_b AND
t3.col_c = t1.col_c);
**这两个版本的功能是否相同?**我的数据库中没有足够的数据来确定。
谢谢。
2条答案
按热度按时间5f0d552i1#
第一个查询是4个表的连接,第二个查询是3个表的连接,所以我不希望两个查询返回相同的行数。
别名
t3
只在ON子句中使用。别名t3
引用ON关键字之前的表。我通过实验发现了这一点。因此前面的查询相当于这可以在传统的连接中转换
第二个查询是
这也可以在传统的连接中转换
这些查询似乎是不同的。为了证明它们的差异,我们使用以下示例:
我们得到以下输出
检索的行数不同,因此
count(*)
也不同。使用化名是令人惊讶的,至少对我来说。
下面的查询可以工作,因为
where_clause
中的t1
引用了table2
。下面的查询可以工作,因为
where_clause
中的t1
引用了table1
。以下查询引发错误,因为
table1
和table2
都包含列col_a
。抛出的错误是
下面的查询有效,别名
t1
引用同一个where_clause
中的两个不同的表。这些和更多的例子可以在这里找到:http://sqlfiddle.com/#!4/84feb/12
最小计数器示例
最小的反例是
这里,第二个查询的结果集为空,第一个查询返回一行。可以证明,第二个查询的
count(*)
永远不会超过第一个查询的count(*)
。更详细的说明
如果我们详细分析下面的陈述,这种行为将变得更加清楚。
以下是此查询的简化语法,采用Backus-Naur形式,源自Oracle 12.2的SQL Language Reference中的语法描述。请注意,在每个语法图下都有一个指向此图的 Backus-Naur 形式的链接,例如Description of the illustration select.eps。“简化”意味着我忽略了所有未使用的可能性,例如
select
定义为我们的查询不使用可选的
for_update_clause
,因此我将规则简化为唯一的例外是可选的
where-clause
。我没有删除它,以便即使我们添加where_clause
,也可以使用此简化规则来分析上述查询。这些简化规则将只定义所有可能的选择语句的子集。
因此,我们的select语句是
query_block
,join_clause
的类型为其中
table_reference
是table1 t
,inner_cross_join_clause
是JOIN table2 t ON (t.col_b = t.col_c)
。省略号...
意味着可能有额外的inner_cross_join_clauses,但我们这里不需要。在
inner_cross_join_clause
中,别名t
引用了table2
。只有当这些引用不能满足时,别名才必须在外部作用域中搜索。因此ON条件中的所有以下表达式都有效:这里
t.col_b
是table2.col_b
,因为t
引用了它的inner_cross_join_clause
的别名,t.col_c
是table1.col_c
。inner_cross_join_clause
的t
(引用table2
)没有列col_c
,因此将搜索外部范围并找到适当的别名。如果我们有条款
别名可以被发现为在该ON-
condition
所属的inner_cross_join_clause
中定义的别名,因此t
将被解析为table2
。如果选择列表包括
而不是
*
,则join_clause
将被搜索别名,t.col_c
将被解析为table1.col_c
(table2
不包含列col_c
),t.col_b
将被解析为table2.col_b
(table1
不包含col_b
),但t.col_a
将引发错误因为对于select_list,没有一个aias定义优先于另一个。如果我们的查询也有一个
where_clause
,那么别名的解析方式就像在select_list
中使用一样。mitkmikd2#
数据越多,结果就越不一样,你同事的查询和这个一样。
或
而你的查询是这样的。
第一个是data where(xx or yy),第二个是data where(xx and yy)。