如何检查所有聚合行中的特定值?

时间:2010-09-16 21:51:07

标签: sql oracle reporting analytics aggregate-functions

假设我有三个表:usergroupxref,这是一个为他们提供多对多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的是:

  

“对于每个用户,请显示他们所在的群组数量。此外,对于每个用户的所有群组名称,请告诉我”开发者“是否为其中一个值。”

实际要求的是:

  

“对于每个用户,请显示他们所在的群组数量。此外,对于每个用户的所有群组名称,请显示此case表达式生成的最高值。”

这是一种反模式的原因是,我基本上依赖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子句的分析函数可能有效,但我想要折叠我正在分组的列,所以它似乎不是一个完美的选择。 / LI>
  • 令人愤怒的是,似乎有一个{{1}}函数记录here,但它只存在于一个叫做Oracle OLAP DML的神秘方言中,我认为我不能仅使用SQL来访问它10克。但是,它似乎完全我想要的东西。

这就是我得到的全部。有什么想法吗?

我认识到有两个非常简单的想法,“在代码中执行”或“在PL / SQL中执行此操作”,但这是作弊。 : - )

3 个答案:

答案 0 :(得分:3)

我会从MAX切换到SUM(使用1而不是Y),因此您要说“计算此人所在群组的名称是开发人员”。

然后该模式类似于“计算购买价值超过30美元的销售数量”。

如果需要,您可以添加另一个表达式来说“如果计数大于零,那么'是'这个人就是开发人员”。非常明确,可能不必要。

答案 1 :(得分:2)

SELECT  user.user_id,
        user.user_name,
        COUNT(*) group_count,
        COUNT(DISTINCT DECODE(group_name, 'Developers', 'Y', NULL)) AS is_developer
        COUNT(DISTINCT DECODE(group_name, 'Content Management', 'Y', NULL)) AS is_content_manager
FROM    the_query

至于ANY,它是一个类似于IN的谓词,而不是一个函数:

SELECT  *
FROM    dual
WHERE   'baz' = ANY('foo', 'bar', 'baz')

答案 2 :(得分:0)

我更喜欢Gary's answer,但如果你想坚持使用布尔返回,你可以通过返回'N'而不是null来使排序更明确。

select
    user.user_id,
    user.user_name,
    count(*) as group_count,
    max( case group.group_name when 'Developers' then 'Y' else 'N' end )
        as is_dev
    max( case group.group_name when 'Content Management' then 'Y' else 'N' 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

(对于写得很好的问题,+ 1)