您的位置:知识库 » 数据库

双重职责问题

作者: DBFocus  来源: 博客园  发布时间: 2011-01-07 10:45  阅读: 397 次  推荐: 0   原文链接   [收藏]  

  问题来自于《SQL puzzles and answers》一书的第36个Puzzle。问题的描述很简单,书中给出了很多种解答,我只能想到其中的1、2种,故在这里进行一下分享。有意思的是书中的解法1是无法通过SQL解析的,大家可以查看原书并进行尝试。本文中的解法在SQL Server 2008中测试通过,可能与原书有部分差异。

  问题描述

  我们有一张权责表:

person role
Smith O
Smith D
Jones O
White D
Brown X

  表中包含2列,person列中存储人名,role列中存储职责代码,O代表Officer,D代表Director等等。创建表的脚本:

use tempdb;

create table Roles
(
person
char(5) not null,
role
char(1) not null
);

insert into
Roles
(
person,
role
)
values
(
'Smith', 'O'),
(
'Smith', 'D'),
(
'Jones', 'O'),
(
'White', 'D'),
(
'Brown', 'X');

需要写一个查询,只关心role为O和D的人。若有人既有职责代码O,又有职责代码D,则合并显示为B。上表的查询结果应为:

person combined_role
Smith B
Jones O
White D

解决方案1

With DirectorRole as
(
select
person,
role
from
Roles
where
role
= 'D'
),
OfficerRole
as
(
select
person,
role
from
Roles
where
role
= 'O'
)
select
coalesce(DirectorRole.person, OfficerRole.person) as person,
case when
(DirectorRole.person
is not null and OfficerRole.person is not null)
then
'B'
else
coalesce(DirectorRole.role, OfficerRole.role)
end as combined_role
from
DirectorRole
full outer join
OfficerRole
on
DirectorRole.person
= OfficerRole.person;


解决方案2

select
person,
'B' as combined_role
from
Roles
where
role
in ('O', 'D')
group by
person
having
COUNT(*) = 2
union all
select
person,
max(role) as combined_role
from
Roles
where
role
in ('O', 'D')
group by
person
having
COUNT(*) = 1

解决方案3

select distinct
R1.person,
case when exists(select
*
from
Roles
as R2
where
R2.person
= R1.person
and
R2.role
<> R1.role
and
R2.role
in ('D', 'O'))
then 'B'
else R1.role
end as combined_role
from
Roles
as R1
where
R1.role
in ('O', 'D');

解决方案4

select
person,
case when
COUNT(*) = 1
then
max(role)
else
'B'
end as combined_role
from
Roles
where
role
in ('D', 'O')
group by
person;

解决方案5

select
person,
case when MIN(role) <> MAX(role)
then 'B'
else MIN(role)
end as combined_role
from
Roles
where
role
in ('D', 'O')
group by
person;

解决方案6

select
person,
SUBSTRING('ODB', sum(charindex(role, 'OD', 1)), 1) as combined_role
from
Roles
where
role
in ('D', 'O')
group by
person;

总结

  从这个例子里可以充分感受到SQL的丰富性,大家可以进一步比较各方法的性能。第6个方案相对前几个方案难理解一些,我在这里多说两句。此查询首先按照人名来分组(这点很重要)。若某人只有一个O职责,charindex函数将返回1;若某人只有一个D职责,charindex函数将返回2;若某人既有O又有D职责,charindex函数将返回2条记录值分别为1和2,经外层聚合函数sum求和后为3。之后substring再将sum的结果值作为索引取‘ODB’中的一个字母。

0
0

数据库热门文章

    数据库最新文章

      最新新闻

        热门新闻