PL/SQL Challenge 每日一题:2019-8-23 连接

[复制链接]
查看11 | 回复3 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
http://www.plsqlchallenge.com/
作者:Kim Berg Hansen
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品

我有一张国家表,还有一张地点表:
create table qz_countries (
ctry_id integer primary key
, ctry_name varchar2(10)
, ctry_region varchar2(4)
);
create table qz_locations (
loc_idinteger primary key
, loc_namevarchar2(10)
, loc_typevarchar2(10)
, ctry_id references qz_countries
);
insert into qz_countries values ( 1, 'Canada' , 'AMER');
insert into qz_countries values (45, 'Denmark', 'EMEA');
insert into qz_countries values (49, 'Germany', 'EMEA');
insert into qz_locations values (1, 'Quebec' , 'Province',1);
insert into qz_locations values (2, 'Toronto', 'Town',1);
insert into qz_locations values (3, 'Jylland', 'Area', 45);
insert into qz_locations values (4, 'Odense' , 'Town', 45);
insert into qz_locations values (5, 'Bayern' , 'State' , 49);
insert into qz_locations values (6, 'Hamburg', 'Town', 49);
commit;
我想要一个类型为'Town'的地点列表,其所在国家处于'EMEA'地区。这个列表必须显示国家名称和地点名称。
哪些选项包含的查询会给我这个所需的输出:
CTRY_NAMELOC_NAME
---------- ----------
DenmarkOdense
GermanyHamburg

(A)
select c.ctry_name, l.loc_name
from qz_countries c, qz_locations l
where c.ctry_region = 'EMEA'
and l.loc_type = 'Town'
and l.ctry_id = c.ctry_id
order by c.ctry_name, l.loc_name;
(B)
select c.ctry_name, l.loc_name
from qz_countries c, qz_locations l
where c.ctry_region = 'EMEA'
and l.loc_type = 'Town'
order by c.ctry_name, l.loc_name;
(C)
select c.ctry_name, l.loc_name
from qz_countries c
join qz_locations l
on l.ctry_id = c.ctry_id
where c.ctry_region = 'EMEA'
and l.loc_type = 'Town'
order by c.ctry_name, l.loc_name;
(D)
select c.ctry_name, l.loc_name
from qz_countries c
join qz_locations l
on l.loc_type = 'Town'
where c.ctry_region = 'EMEA'
order by c.ctry_name, l.loc_name;
(E)
select c.ctry_name, l.loc_name
from qz_countries c
natural join qz_locations l
where c.ctry_region = 'EMEA'
and l.loc_type = 'Town'
order by c.ctry_name, l.loc_name;
(F)
select c.ctry_name, l.loc_name
from qz_countries c
where c.ctry_region = 'EMEA'
join qz_locations l
where l.loc_type = 'Town'
order by c.ctry_name, l.loc_name;

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案:ACE
A: ctry_id 是连接字段,其他两个是过滤条件
B: 没有写关键的连接条件
C: ANSI的连接语法,join 后面跟连接条件,where子句跟过滤条件
D: join 后面跟连接条件写的连接字段错误
E: 父子表中ctry_id 是连接字段名是相同的,连接时natural join会选择ctry_id 做连接
F: 语法错误,join子句应在where子句的前面
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
A、C、E
A: 最常见的标准sql写法;
B: 无关联连接条件,会出现笛卡尔集;
C: join 连接条件写法;
D: join 后连接条件错误,达不到预期结果集;
E: natural join写法;
F: 语法错误;
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ACE, 2楼得奖。
A: 这是经典的历史遗迹式的连接风格,已经很好地运行了几十年,把过滤和连接谓词同时放在WHERE子句中。
B: 哎呦, 我们忘记了连接谓词,仅仅定义了过滤谓词,所以在这个错误的输出中,我们得到了EMEA中的所有国家以及所有类型为TOWN的地点之间的笛卡儿积:
CTRY_NAMELOC_NAME
---------- ----------
DenmarkHamburg
DenmarkOdense
DenmarkToronto
GermanyHamburg
GermanyOdense
GermanyToronto
C: 利用ANSI的连接风格我们隔离了 ON 子句中的连接谓词以及WHERE子句中的过滤谓词。这给出了和A选项相同的正确结果。
D: 在这里就清楚多了(相比起选项B),我们漏掉了连接谓词,因为ON子句中并没有真正包含连接谓词,而是过滤谓词之一。原则上你可能希望这会引发一个错误,因为它没有真正的意义,但在幕后它被重写成与选择B相同,得到的错误输出也相同。所以这不会在这里自动捕获你的错误,但是首先你不太可能犯这个错误,因为在你写ON子句时,你脑子里就会知道放在这里的必须是连接谓词。
E: 既然我们在连接子句中所用的列名在两张表中恰好相同(并且是两张表中唯一名字相同的列),那么就有可能通过使用NATURAL JOIN避免连接谓词并且仍然得到正确的结果。但是这有些危险,因为如果一个表中的新列恰好与另一个表中的列名相同,则向表中添加新列可能会灾难性地更改连接。
F: 这是完全错误的连接语法,因为我们缺少关于如何连接的说明(例如ON子句或NATURAL JOIN)。 WHERE子句也不能重复 ---- 即使我们在两个表上都有过滤谓词,它们也需要在所有连接之后进入单个WHERE子句。此选择会引发错误:
ORA-00933: SQL command not properly ended.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行