在查询中两次使用相同的 table 别名
Using the same table alias twice in a query
我的同事是 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 子句使用相同的 table 别名 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);
这两个版本在功能上是否相同?我的数据库中确实没有足够的数据尚待确定。
谢谢。
随着数据的增多,会产生不同的结果。
您的同事查询与此相同。
select * from table3 where t3.col_b = 'XX'
union
select * from table3 where t3.col_c = 'YY'
或
select * from table3 where t3.col_b = 'XX' or t3.col_c = 'YY'
而你的查询是这样的。
select * from table3 where t3.col_b ='XX' and t3.col_c='YY'
第一个类似于数据(xx 或 yy),第二个类似于数据(xx 和 yy)
第一个查询是 4 tables 的连接,第二个是 3tables 的连接。所以我不希望这两个查询 return 相同的行数。
SELECT *
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);
别名t3
仅在ON 子句中使用。别名 t3
指的是 ON 关键字之前的 table。我通过实验发现了这一点。所以之前的查询等价于
SELECT *
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 t4 ON
(t4.col_c = t1.col_c);
这可以在传统连接中转换
SELECT *
FROM table1 t1,
table2 t2,
table3 t3,
table3 t4
where (t1.col_a = t2.col_a)
and (t2.col_b = t3.col_b)
and (t4.col_c = t1.col_c);
第二个查询是
SELECT *
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);
这也可以转化为传统的join
SELECT *
FROM table1 t1,
table2 t2,
table3 t3
where (t1.col_a = t2.col_a)
and (t2.col_b = t3.col_b)
AND (t3.col_c = t1.col_c);
这些查询似乎有所不同。为了证明它们的差异,我们使用以下示例:
create table table1(
col_a number,
col_c number
);
create table table2(
col_a number,
col_b number
);
create table table3(
col_b number,
col_c number
);
insert into table1(col_a, col_c) values(1,3);
insert into table1(col_a, col_c) values(4,3);
insert into table2(col_a, col_b) values(1,2);
insert into table2(col_a, col_b) values(4,2);
insert into table3(col_b, col_c) values(2,3);
insert into table3(col_b, col_c) values(2,5);
insert into table3(col_b, col_c) values(7,9);
commit;
我们得到以下输出
SELECT *
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)
| COL_A | COL_C | COL_A | COL_B | COL_B | COL_C | COL_B | COL_C |
|-------|-------|-------|-------|-------|-------|-------|-------|
| 1 | 3 | 1 | 2 | 2 | 3 | 2 | 3 |
| 4 | 3 | 4 | 2 | 2 | 3 | 2 | 3 |
| 1 | 3 | 1 | 2 | 2 | 5 | 2 | 3 |
| 4 | 3 | 4 | 2 | 2 | 5 | 2 | 3 |
SELECT *
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)
| COL_A | COL_C | COL_A | COL_B | COL_B | COL_C |
|-------|-------|-------|-------|-------|-------|
| 4 | 3 | 4 | 2 | 2 | 3 |
| 1 | 3 | 1 | 2 | 2 | 3 |
检索到的行数不同,因此count(*)
不同。
别名的使用令人惊讶。至少对我来说。
以下查询有效,因为 where_clause
中的 t1
引用了 table2
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_b<0;
以下查询有效,因为 where_clause
中的 t1
引用了 table1
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_c<0;
以下查询会引发错误,因为 table1
和 table2
都包含列 col_a
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_a<0;
抛出的错误是
ORA-00918: column ambiguously defined
以下查询有效,别名 t1
指的是同一 where_clause
.
中的两个不同的 table
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_b<0 and t1.col_c<0;
可以在此处找到这些以及更多示例:http://sqlfiddle.com/#!4/84feb/12
最小计数器示例
最小的计数器例子是
table1
col_a col_c
1 2
table2
col_a col_b
1 3
table3
col_b col_c
3 5
6 2
这里第二个查询有一个空结果集,第一个查询 return 有一行。可以看出,第二个查询的 count(*)
永远不会执行第一个查询的 count(*)
。
更详细的解释
如果我们详细分析下面的语句,这种行为会变得更加清楚。
SELECT t.col_b, t.col_c
FROM table1 t
JOIN table2 t ON
(t.col_b = t.col_c) ;
这是从 SQL Language Reference of Oracle 12.2. Note that under each syntax diagram there is a link to the Backus–Naur form of this diagram, e.g Description of the illustration select.eps 中的语法描述派生的 Backus–Naur 形式的此查询的简化语法。 “减少”意味着我排除了所有未使用的可能性,例如select
定义为
select::=subquery [ for_update_clause ] ;
我们的查询不使用可选的 for_update_clause
,所以我将规则缩减为
select::=subquery
唯一的豁免是可选的 where-clause
。我没有删除它,以便即使我们添加 where_clause
.
也可以使用此简化规则来分析上述查询
这些简化的规则将只定义所有可能的 select 语句的一个子集。
select::=subquery
subquery::=query_block
query_block::=SELECT select_list FROM join_clause [ where_clause ]
join_clause::=table_reference inner_cross_join_clause ...
table_reference::=query_table_expression t_alias query_table_expression::=table
inner_cross_join_clause::=JOIN table_reference ON condition
所以我们的 select 语句是 query_block
而 join_clause
是类型
table_reference inner_cross_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
。仅当无法满足这些引用时,才必须在外部范围内搜索别名。所以 ONcondition 中的以下所有表达式都是有效的:
t.col_b = t.col_c
这里的t.col_b
是table2.col_b
,因为t
是指它的inner_cross_join_clause
的别名,t.col_c
是table1.col_c
。 inner_cross_join_clause
(参考table2
)的t
没有列col_c
,因此将搜索外部范围并找到合适的别名。
如果我们有子句
t.col_a = t.col_a
别名可以在这个 ON-condition
所属的 inner_cross_join_clause
中找到,因此 t
将被解析为 table2
.
如果 select 列表包含
t.col_c, t.col_b, t.col_a
而不是 *
那么 join_clause
将被搜索别名并且 t.col_c
将被解析为 table1.col_c
(table2
不包含别名列 col_c
),t.col_b
将解析为 table2.col_b
(table1
不包含 col_b
)但 t.col_a
将引发错误
ORA-00918: column ambiguously defined
因为对于 select_list none 的 aias 定义有优先级。如果我们的查询也有一个 where_clause
那么别名的解析方式就好像它们在 select_list
.
中一样
我的同事是 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 子句使用相同的 table 别名 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);
这两个版本在功能上是否相同?我的数据库中确实没有足够的数据尚待确定。
谢谢。
随着数据的增多,会产生不同的结果。 您的同事查询与此相同。
select * from table3 where t3.col_b = 'XX'
union
select * from table3 where t3.col_c = 'YY'
或
select * from table3 where t3.col_b = 'XX' or t3.col_c = 'YY'
而你的查询是这样的。
select * from table3 where t3.col_b ='XX' and t3.col_c='YY'
第一个类似于数据(xx 或 yy),第二个类似于数据(xx 和 yy)
第一个查询是 4 tables 的连接,第二个是 3tables 的连接。所以我不希望这两个查询 return 相同的行数。
SELECT *
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);
别名t3
仅在ON 子句中使用。别名 t3
指的是 ON 关键字之前的 table。我通过实验发现了这一点。所以之前的查询等价于
SELECT *
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 t4 ON
(t4.col_c = t1.col_c);
这可以在传统连接中转换
SELECT *
FROM table1 t1,
table2 t2,
table3 t3,
table3 t4
where (t1.col_a = t2.col_a)
and (t2.col_b = t3.col_b)
and (t4.col_c = t1.col_c);
第二个查询是
SELECT *
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);
这也可以转化为传统的join
SELECT *
FROM table1 t1,
table2 t2,
table3 t3
where (t1.col_a = t2.col_a)
and (t2.col_b = t3.col_b)
AND (t3.col_c = t1.col_c);
这些查询似乎有所不同。为了证明它们的差异,我们使用以下示例:
create table table1(
col_a number,
col_c number
);
create table table2(
col_a number,
col_b number
);
create table table3(
col_b number,
col_c number
);
insert into table1(col_a, col_c) values(1,3);
insert into table1(col_a, col_c) values(4,3);
insert into table2(col_a, col_b) values(1,2);
insert into table2(col_a, col_b) values(4,2);
insert into table3(col_b, col_c) values(2,3);
insert into table3(col_b, col_c) values(2,5);
insert into table3(col_b, col_c) values(7,9);
commit;
我们得到以下输出
SELECT *
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)
| COL_A | COL_C | COL_A | COL_B | COL_B | COL_C | COL_B | COL_C |
|-------|-------|-------|-------|-------|-------|-------|-------|
| 1 | 3 | 1 | 2 | 2 | 3 | 2 | 3 |
| 4 | 3 | 4 | 2 | 2 | 3 | 2 | 3 |
| 1 | 3 | 1 | 2 | 2 | 5 | 2 | 3 |
| 4 | 3 | 4 | 2 | 2 | 5 | 2 | 3 |
SELECT *
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)
| COL_A | COL_C | COL_A | COL_B | COL_B | COL_C |
|-------|-------|-------|-------|-------|-------|
| 4 | 3 | 4 | 2 | 2 | 3 |
| 1 | 3 | 1 | 2 | 2 | 3 |
检索到的行数不同,因此count(*)
不同。
别名的使用令人惊讶。至少对我来说。
以下查询有效,因为 where_clause
中的 t1
引用了 table2
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_b<0;
以下查询有效,因为 where_clause
中的 t1
引用了 table1
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_c<0;
以下查询会引发错误,因为 table1
和 table2
都包含列 col_a
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_a<0;
抛出的错误是
ORA-00918: column ambiguously defined
以下查询有效,别名 t1
指的是同一 where_clause
.
select *
from table1 t1 join table2 t1 on(1=1)
where t1.col_b<0 and t1.col_c<0;
可以在此处找到这些以及更多示例:http://sqlfiddle.com/#!4/84feb/12
最小计数器示例
最小的计数器例子是
table1
col_a col_c
1 2
table2
col_a col_b
1 3
table3
col_b col_c
3 5
6 2
这里第二个查询有一个空结果集,第一个查询 return 有一行。可以看出,第二个查询的 count(*)
永远不会执行第一个查询的 count(*)
。
更详细的解释
如果我们详细分析下面的语句,这种行为会变得更加清楚。
SELECT t.col_b, t.col_c
FROM table1 t
JOIN table2 t ON
(t.col_b = t.col_c) ;
这是从 SQL Language Reference of Oracle 12.2. Note that under each syntax diagram there is a link to the Backus–Naur form of this diagram, e.g Description of the illustration select.eps 中的语法描述派生的 Backus–Naur 形式的此查询的简化语法。 “减少”意味着我排除了所有未使用的可能性,例如select
定义为
select::=subquery [ for_update_clause ] ;
我们的查询不使用可选的 for_update_clause
,所以我将规则缩减为
select::=subquery
唯一的豁免是可选的 where-clause
。我没有删除它,以便即使我们添加 where_clause
.
这些简化的规则将只定义所有可能的 select 语句的一个子集。
select::=subquery
subquery::=query_block
query_block::=SELECT select_list FROM join_clause [ where_clause ]
join_clause::=table_reference inner_cross_join_clause ...
table_reference::=query_table_expression t_alias query_table_expression::=table
inner_cross_join_clause::=JOIN table_reference ON condition
所以我们的 select 语句是 query_block
而 join_clause
是类型
table_reference inner_cross_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
。仅当无法满足这些引用时,才必须在外部范围内搜索别名。所以 ONcondition 中的以下所有表达式都是有效的:
t.col_b = t.col_c
这里的t.col_b
是table2.col_b
,因为t
是指它的inner_cross_join_clause
的别名,t.col_c
是table1.col_c
。 inner_cross_join_clause
(参考table2
)的t
没有列col_c
,因此将搜索外部范围并找到合适的别名。
如果我们有子句
t.col_a = t.col_a
别名可以在这个 ON-condition
所属的 inner_cross_join_clause
中找到,因此 t
将被解析为 table2
.
如果 select 列表包含
t.col_c, t.col_b, t.col_a
而不是 *
那么 join_clause
将被搜索别名并且 t.col_c
将被解析为 table1.col_c
(table2
不包含别名列 col_c
),t.col_b
将解析为 table2.col_b
(table1
不包含 col_b
)但 t.col_a
将引发错误
ORA-00918: column ambiguously defined
因为对于 select_list none 的 aias 定义有优先级。如果我们的查询也有一个 where_clause
那么别名的解析方式就好像它们在 select_list
.