【发布时间】:2010-09-16 21:51:07
【问题描述】:
假设我有三个表: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 的是:
“对于每个用户,告诉我他们在多少个组中。另外,对于每个用户的所有组名,告诉我'Developers' 是否是值之一。”
我实际上要问的是:
“对于每个用户,告诉我他们在多少个组中。另外,对于每个用户的所有组名,告诉我这个
case表达式产生的最大值。”
这是一个反模式的原因是我基本上依赖于这样一个事实,即当使用max() 评估时,Y 发生 在null 上方“冒泡”。如果有人想复制或扩充此查询,他们很容易忘记反模式并意外地将返回值更改为不使用相同不直观巧合的内容。
基本上,我希望我能写的查询是这样的:
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 中执行”,但这是作弊。 :-)
【问题讨论】:
-
用户可以同时属于开发者和内容管理者吗?这就是你需要两个单独的列的原因吗?
-
我没有将 [SQL] 放在标题中,而是仅依靠“sql”标签。
-
@be here now- 是的,这就是原因。
-
@Nick Pierpoint - 当你写关于 SO 的问题时,它会根据标题为你提供一个潜在类似问题的列表。其他一些问题都以 [SQL] 开头,我发现它是一种有用的方式来查找实际上相关的“相似”建议。所以,我复制了约定! :-)
-
我认为在标题中放置标签不是惯例:stackoverflow.com/questions/tagged/sql
标签: sql oracle reporting analytics aggregate-functions