使用SQL Server,我试图从我没有设计的表中查询一种平均计数,基本上我想要一个列表,按一列分组,另一列的不同值的数量匹配a给定标准,那些,与另一个标准匹配的行数(我将用它来创建平均计数或其他任何标准)。这可不难,但我的理论日设定不好,任何指针都会感激不尽。
这是简化和通用化的场景(下面的架构和示例数据)。假设我们有三列:
objid
(具有聚集索引) userid
(没有索引,我可以添加一个) actiontype
(没有索引,我可以添加一个) 这些都不是唯一的,没有一个是null
。我们希望完全忽略actiontype
为none
的所有行。根据{{1}},我们希望知道每个用户与之互动的对象平均有多少userid
行。
因此,如果我们有“ahmed”,“joe”和“maria”,并且joe与3个对象进行了交互并提出了5个标志,那么actiontype = 'flag'
个数字是连续的;如果“艾哈迈德”与3个物体互动并且没有举起任何旗帜,他的号码将是5 / 3 = 1.6666
;如果“玛丽亚”与5个物体互动并举起4个旗帜,她的号码将是0
:
+--------+------------------+ | userid | flags_per_object | +--------+------------------+ | ahmed | 0 | | joe | 1.66666667 | | maria | 0.8 | +--------+------------------+
如果将其作为副本关闭,我不会感到惊讶,我只是找不到它。
这是简化的表格设置和示例数据:
4 / 5 = 0.8
答案 0 :(得分:5)
您可以尝试以下操作:
select t1.userid,
CASE cnt2
WHEN 0 THEN 0
ELSE ISNULL(cast(cnt2 as float)/cnt1,0)
END as num
FROM
(
select userid, COUNT(distinct(t1.objid)) as cnt2
from tmp as t1
where t1.actiontype <> 'none'
group by t1.userid
) t1
LEFT JOIN (
SELECT t2.userid, COUNT(*) as cnt1
FROM tmp as t2
WHERE t2.actiontype='flag'
GROUP BY t2.userid)b ON (b.userid = t1.userid)
即使它看起来比您的解决方案更糟糕,但令人惊讶的是,它会根据您提供的测试数据生成更好的执行计划。
答案 1 :(得分:2)
我确实有一些有用的东西:
select userid,
cast(count(case when actiontype = 'flag' then 1 else null end) as float)
/
count(distinct(objid))
as flags_per_object
from tmp
where actiontype <> 'none'
group by userid
....但我不禁觉得有更好的方法......
答案 2 :(得分:1)
;with cte as
(
select userid,
sum(case actiontype when 'flag'
then 1
else 0
end) as Flags
from tmp
where actiontype <> 'none'
group by userid, [objid]
)
select userid,
cast(sum(Flags) as float)/count(*) as flags_per_object
from cte
group by userid
作为子查询而不是CTE
select userid,
cast(sum(Flags) as float)/count(*) as flags_per_object
from (select userid,
sum(case actiontype when 'flag'
then 1
else 0
end) as Flags
from tmp
where actiontype <> 'none'
group by userid, [objid]) as T
group by userid
答案 3 :(得分:1)
答案是:取决于。
在我的测试中,无论我使用什么测试数据,我的解决方案都是最慢的。使用真实数据,它的速度大约是最快解决方案的一半。
对于我的问题中引用的测试数据,Mikael's solution更快,对于我现实生活中的表格中更大但仍然很小的数据集(我们的测试系统,大约2k行),速度更快。
但a1ex07's solution对于我的全尺寸现实生活表(我们的实时系统,约700k行)来说更快。 a1ex07和Mikael之间的距离不是很远,但a1ex07肯定有优势。
我最终实际上使用的是Mikael的解决方案,因为如果你不是一个l33t的DB人员(并且对这段代码进行维护的人,其中SQL只是一小部分,那么它会更容易概念化) be)并且更容易适应各种其他场景。
因此,这个社区维基元回答,我会在时间限制过去时接受,而不是接受他们的优秀答案。如果您认为这有帮助,请像我一样对Mikael's answer和a1ex07's answer进行投票。
答案 4 :(得分:0)
SELECT
userid,
flags_per_object =
COUNT(CASE actiontype WHEN 'flag' THEN objid END) *
1.0 / COUNT(DISTINCT objid)
FROM
tmp
WHERE actiontype <> 'none'
GROUP BY userid