假设我有三个表:user
, group
和xref
,一个为他们提供多对多 RI 的表。
我可能想查看每个用户所属的组:
select
user.user_id,
user.user_name,
count(*) as group_count
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
到目前为止一切正常。但是,如果我想要一些额外的信息怎么办?我正在报告,我想知道每个用户是开发人员还是内容管理员。现在,出现了一种反模式:
select
user.user_id,
user.user_name,
count(*) as group_count,
max( case group.group_name when 'Developers' then 'Y' else null end )
as is_dev
max( case group.group_name when 'Content Management' then 'Y' else null end )
as is_cm
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
这有效,并产生了预期的结果,但感觉非常错误。我想问Oracle的是:
"For each user, show me how many groups they're in. Also, for all group names per user, show me if 'Developers' is one of the values."
我实际上要问的是:
"For each user, show me how many groups they're in. Also, for all group names per user, show me the highest value produced by this
case
expression."
这是一种反模式的原因是我基本上依赖于这样一个事实:Y
碰巧在 null
上方“冒泡”当使用 max()
进行评估时。如果有人想要复制或扩充此查询,他们可能很容易忘记反模式,并意外地将返回值更改为不使用相同的不直观巧合的值。
基本上,我希望编写的查询是这样的:
select
user.user_id,
user.user_name,
count(*) as group_count,
any(group.group_name, 'Developers', 'Y', null) as is_dev,
any(group.group_name, 'Content Management', 'Y', null) as is_cm
from
user
inner join xref on user.user_id = xref.user_id
inner join group on group.group_id = xref.group_id
group by user.user_id, user.user_name
我一直在寻找选择,似乎有一些潜力:
-
first_value
可以工作,但我不知道如何限制相应的partition
窗口向右行。 - 具有
over
的分析函数子句可能有效,但我确实想要折叠分组所依据的列,所以它似乎不是一个完美的选择。 - 令人愤怒的是,似乎有一个
any
功能记录here ,但它仅存在于一种名为 Oracle OLAP DML 的神秘方言中,我认为在 10g 上仅使用 SQL 无法访问它。但是,它似乎完全符合我的要求。
这就是我所得到的。有什么想法吗?
我认识到有两个非常简单的想法,“在代码中执行”或“在 PL/SQL 中执行”,但这是作弊。 :-)
最佳答案
我会从 MAX 切换到 SUM(使用 1 而不是 Y),因此您会说“计算此人所在组名称为 Developers 的组数”。
该模式类似于“计算购买值(value)超过 30 美元的销售数量”。
如果需要,您可以添加另一个表达式来表示“如果计数大于零,则‘是’此人是开发人员”。非常明确,但可能没有必要。
关于sql - 如何检查所有聚合行中的某个值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3731102/