PL/SQL Challenge 每日一题:2017-4-1 集合操作

[复制链接]
查看11 | 回复6 | 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已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
我有两张表,保存着高尔夫(golf)和飞镖(dart)的选手:
create table qz_golf_players (
lastnamevarchar2(20)
, firstname varchar2(20)
, unique (lastname, firstname)
)
/
create table qz_dart_players (
lastnamevarchar2(20)
, firstname varchar2(20)
, unique (lastname, firstname)
)
/
insert into qz_golf_players values ('Hammersmith', 'Christopher')
/
insert into qz_golf_players values ('Lovejoy', 'Julian' )
/
insert into qz_golf_players values ('Sinclair' , 'Michael')
/
insert into qz_dart_players values ('Carlisle' , 'Edmund' )
/
insert into qz_dart_players values ('Hammersmith', 'Christopher')
/
insert into qz_dart_players values ('Lovejoy', 'Julian' )
/
commit
/
有些人两种都玩,但是我想要一个清单,列出哪些人仅仅只玩一种。
哪些选项包含的查询会返回这个输出:
LASTNAME
FIRSTNAME
-------------------- --------------------
Carlisle
Edmund
Sinclair
Michael
(A)
select lastname, firstname
from (
select lastname, firstname
from qz_golf_players
UNION ALL
select lastname, firstname
from qz_dart_players
)
group by lastname, firstname
having count(*) = 1
order by lastname, firstname
/
(B)
select lastname, firstname
from (
select lastname, firstname
from qz_golf_players
UNION
select lastname, firstname
from qz_dart_players
)
group by lastname, firstname
having count(*) = 1
order by lastname, firstname
/
(C)
select lastname, firstname
from qz_golf_players
UNION
select lastname, firstname
from qz_dart_players
MINUS
select lastname, firstname
from qz_golf_players
INTERSECT
select lastname, firstname
from qz_dart_players
order by lastname, firstname
/
(D)
(
select lastname, firstname
from qz_golf_players
UNION
select lastname, firstname
from qz_dart_players
)
MINUS
(
select lastname, firstname
from qz_golf_players
INTERSECT
select lastname, firstname
from qz_dart_players
)
order by lastname, firstname
/
(E)
(
select lastname, firstname
from qz_golf_players
UNION ALL
select lastname, firstname
from qz_dart_players
)
MINUS
(
select lastname, firstname
from qz_golf_players
INTERSECT
select lastname, firstname
from qz_dart_players
)
order by lastname, firstname
/
(F)
(
select lastname, firstname
from qz_golf_players
MINUS
select lastname, firstname
from qz_dart_players
)
UNION ALL
(
select lastname, firstname
from qz_dart_players
MINUS
select lastname, firstname
from qz_golf_players
)
order by lastname, firstname
/
(G)
select lastname, firstname
from qz_golf_players g
where not exists (
select null
from qz_dart_players d
where d.lastname= g.lastname
and d.firstname = g.firstname
)
UNION ALL
select lastname, firstname
from qz_dart_players d
where not exists (
select null
from qz_golf_players g
where g.lastname= d.lastname
and g.firstname = d.firstname
)
order by lastname, firstname
/
(H)
select coalesce(g.lastname , d.lastname ) as lastname
, coalesce(g.firstname, d.firstname) as firstname
from qz_golf_players g
FULL OUTER JOIN qz_dart_players d
on d.lastname= g.lastname
and d.firstname = g.firstname
where g.lastname is null
or d.lastname is null
order by lastname, firstname
/

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
我觉得A,D,F,G,H是对的
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
除了B,C不可以,ADEFGH 都可以
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
还以为是pl/sql的几种集合,点进来才发现是sql的
(a u b)-(a n b)应该是对的,不知道不加括号优先级是怎样的
除了union all都会排重,输出行顺序也会变,所以题目都用了order by
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ADEFGH, 3楼得奖。
A: 利用UNION ALL, 那些两种都玩的人在内联视图返回的结果集中就会有重复的行。所以一个GROUP BY带有HAVING子句来得到那些在内联视图中仅仅有一行的人,这样就可以给出我们想要的结果。
B: 如果用UNION 而不是UNION ALL就会在内联视图返回的结果集上做一个隐式的DISTINCT操作。因此不会有可以过滤的重复记录,这个选项错误地返回了所有的选手:
LASTNAME
FIRSTNAME
-------------------- --------------------
Carlisle
Edmund
Hammersmith
Christopher
Lovejoy
Julian
Sinclair
Michael
C: 集合操作总是按顺序执行的,所以UNION先返回4名选手,然后MINUS去除了高尔夫选手,剩下只玩飞镖的选手。和飞镖选手的INTERSECT留给我们的仍然是那个飞镖选手,得到这个错误的结果:
LASTNAME
FIRSTNAME
-------------------- --------------------
Carlisle
Edmund
D: 利用括号来控制集合操作的顺序,这样就能得到所需的结果,因为此处我们先得到一个完整的选手集合(UNION的结果),然后减去(MINUS)那些两种都玩的人(INTERSECT)。第一对括号并不是严格要求的,但是它们确实把代码的目的清晰化了。
E: 因为我们在第一个子查询中用了UNION ALL,很容易就会想到,既然两种都玩的人会有重复,那么MINUS就只会去除重复中的一个。但是并非如此,因为MINUS 和 INTERSECT 都会执行一个隐式的 DISTINCT操作,使得最终结果和前一选项相同。
F: 和前两个选项的逻辑不同的是,我们也可以得到那些只玩高尔夫(第一个MINUS子查询)和只玩飞镖(第二个MINUS子查询)的人然后把两个结果UNION ALL变成所需的结果。
G: 要得到之玩高尔夫和只玩飞镖的人,也可以用 NOT EXISTS而不用MINUS,其余逻辑和前一选项相同。
H: 另一方法就是作一个FULL OUTER JOIN,然后选出那些只存在于一个表中的行。

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
newkid 发表于 2017-4-20 04:11
答案ADEFGH, 3楼得奖。
A: 利用UNION ALL, 那些两种都玩的人在内联视图返回的结果集中就会有重复的行。 ...

F的union all改为union 也没错
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
newkid 发表于 2017-4-20 04:11
答案ADEFGH, 3楼得奖。
A: 利用UNION ALL, 那些两种都玩的人在内联视图返回的结果集中就会有重复的行。 ...

第一次得奖啊
回复

使用道具 举报

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

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行