Sql 如何在所有聚合行中检查某个值?
假设我有三个表:Sql 如何在所有聚合行中检查某个值?,sql,oracle,reporting,analytics,aggregate-functions,Sql,Oracle,Reporting,Analytics,Aggregate Functions,假设我有三个表: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.gr
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的是:
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
“对于每个用户,请向我显示他们所在的组数。此外,对于每个用户的所有组名,请向我显示“开发人员”是否为其中一个值。”
我真正想问的是:
“对于每个用户,请向我显示他们所在的组数。此外,对于每个用户的所有组名,请向我显示此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\u value
可以工作,但我不知道如何将相应的分区
窗口限制到正确的行
- 带有
over
子句的分析函数可能会工作,但我确实希望折叠我分组所依据的列,因此它似乎不是一个完美的匹配
- 令人恼火的是,似乎有一个
any
函数被记录在案,但它只存在于一种神秘的方言中,称为Oracle OLAP DML,我认为我不能仅使用SQL在10g上访问它。但是,它似乎正是我想要的
我只有这些了。有什么想法吗
我知道有两个非常简单的想法,“在代码中实现”或“在PL/SQL中实现”,但这是欺骗。:-) 我会从MAX切换到SUM(用1而不是Y),所以你说的是“计算这个人所在的组的数量,其中组名是Developers”
然后,这种模式类似于“计算购买价值超过30美元的销售数量”
如果需要,您可以添加另一个表达式,表示“如果计数大于零,那么‘是’此人是开发人员”。非常明确,但可能没有必要
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
,它是类似于中的的谓词,而不是函数:
SELECT *
FROM dual
WHERE 'baz' = ANY('foo', 'bar', 'baz')
我更喜欢,但是如果您想坚持使用布尔返回,您可以通过返回'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表示写得很好的问题)投了赞成票,因为SUM()
似乎不是什么好办法。但是,我现在坚持接受任何答案。谢谢用户是否同时属于开发人员和内容管理人员?这就是你需要两个独立列的原因吗?与其在标题中添加[SQL],我只需要使用“SQL”标记。@现在到这里-是的,这就是原因。@Nick Pierpoint-当你在上面写问题时,它会根据标题为你提供一个潜在的类似问题列表。其他一些问题是在[SQL]前面加上的,我发现这是一种有用的方法,可以找到实际上相关的“类似”建议。所以,我复制了公约!:-)我不认为在标题中添加标签是一种惯例:感谢+1和答案。不幸的是,“N”成为了我在问题中提到的同一个问题的受害者,这就是你依赖的事实是“N”恰好排序高于“Y”。例如,如果您使用的不是“Y”和“N”,而是“Always”和“Never”,那么每个单元格都将是“Never”,因为max
将始终拾取它。这是一个不直观的“明白了”,我相信这是一个真正的反模式的一部分。正如我所说,我更喜欢计数,但我认为你使用Y和N作为标志是非常安全的。