【问题标题】:Selecting row from table meeting two count conditions从满足两个计数条件的表中选择行
【发布时间】:2014-10-10 02:43:41
【问题描述】:

我有一个由用户、练习和分数组成的表格。下面可以看到表格的结构和一些示例数据(仅供参考)。

|UserID | ExerciseID | Score |
------------------------------
|1 | 1 | 0 |
|1 | 2 | 1 |
|2 | 1 | 1 |
|2 | 2 | 0 |

此表包含大约 92000 个评分(每行是唯一的三个)。我希望收到该表的一个子集,其中包含最活跃的用户练习。最活跃意味着例如在表中出现超过 20 次。所以我希望用户完成了超过 20 次不同的练习,并且我希望不同的用户完成了超过 20 次的练习。

有点循环推理,因为我希望用户完成了 20 个或更多不同的活动练习,这些练习必须是活动的,因为它们应该由 20 个或更多用户完成,并且那些用户应该是活跃的等等等等..

我希望这可以通过查询来实现,我已经尝试过自己并提出了一个接近我想要的结果的查询,但结果并不完全准确(因为有一个用户只完成了16 个练习和 2 个已被其他用户完成 19 次的练习)。查询有点难看,但它是:

select UserID, ExerciseID, Score
from [FrenchExercises]
where ExerciseID in (   select ExerciseID
                    from [FrenchExercises]
                    where UserID in (SELECT UserID
                                        FROM [FrenchExercises]
                                        GROUP BY UserID
                                        HAVING count(ExerciseID) >= 20)
                    group by ExerciseID
                    having count(UserID) >= 20)
    AND UserID in ( select UserID
                    from [FrenchExercises]
                    where ExerciseIDin (SELECT ExerciseID
                                        FROM [FrenchExercises]
                                        GROUP BY ExerciseID
                                        HAVING count(UserID) >= 20)
                    group by UserID
                    having count(ExerciseID) >= 20)

第一个子查询选择最活跃的用户,然后从活跃用户列表中选择最活跃的用户练习。第二个查询从锻炼的角度做同样的事情,它选择最活跃的锻炼,然后选择选择了这些锻炼的最活跃的用户。当我想组合这两个查询并选择ExerciseID、UserID 和Score 时,我发现结果并不完全正确。

我猜我的查询有一些错误,或者我采取了完全错误的方法。任何想法将不胜感激。

【问题讨论】:

  • 为什么不只是 select UserID, count(distinct ExerciseID) as exercises from [FrenchExercises] group by UserIDselect ExerciseID, count(distinct UserID) as users from [FrenchExercises] group by ExerciseID
  • @juergend - 他不想要单独的结果。他希望查询显示回答了最“活跃”问题的最活跃用户。所以,这不是一个简单的答案。
  • 这听起来像是协同集群,在 SQL Server 中会有点棘手。
  • @juergend Borat Sagdiyev 是对的,我不想要单独的结果。 Gordon Linoff,关于如何在 SQL Server 中处理的任何想法?还是用不同的方法解决更好?
  • 什么是“活跃用户”?有做过20+练习的用户吗?

标签: sql sql-server select count having


【解决方案1】:

根据一些cmets编辑:

select userid, exerciseid, score
  from frenchexercises
 where userid in (select userid
                    from frenchexercises
                   group by userid
                  having count(*) >= 20)
   and exerciseid in (select exerciseid
                        from frenchexercises
                       group by exerciseid
                      having count(distinct userid) >= 20)

小提琴演示: http://sqlfiddle.com/#!6/a2cc6/6/0

在示例数据中,我有 USERID #1 执行 20 次练习。练习 #1 到 #20。这些练习中只有一个是“主动”的。练习 #1 由除用户 #1 之外的其他 20 人执行,因此它处于活动状态。其余的都没有。

用户 #1 在输出中返回,但只列出了练习 #1,因为这是他执行的唯一主动练习。

这个查询和我之前查询的区别在于,用户 #1 不会被认为是活跃的,因为他没有参加 20 次或更多的活跃练习。他只参加了 20 次或更多的 ANY 练习。 这就是我改变的。

如果后者确实是你真正想要的,这里是前面的查询:

select userid, exerciseid, score
  from frenchexercises
 where userid in (select userid
                    from frenchexercises
                   where exerciseid in
                         (select exerciseid
                            from frenchexercises
                           group by exerciseid
                          having count(distinct userid) >= 20)
                   group by userid
                  having count(*) >= 20)
   and exerciseid in (select exerciseid
                        from frenchexercises
                       group by exerciseid
                      having count(distinct userid) >= 20)

同样,如果用户还参加了 20 多次活跃练习,则上述查询只会考虑用户活跃。

【讨论】:

  • 在这两种方法中,只选择活跃用户而不选择活跃练习。我需要一些可以同时选择它们的东西。
  • @FlorisDevriendt 该查询确实为执行 20 次或更多主动练习(正确)但没有限制(对于此类用户)显示他们可能还参与的其他“非活动练习”的结果的用户中。我刚刚更改了答案以解决最后一部分。
  • 这两个查询都为我提供了进行了 20 次或更多主动练习的用户。那是正确的。但是查询不返回活动练习,它只返回在活动练习中执行的活动用户(以及任何其他练习)。我想要的是 活跃用户(参与活跃练习)和活跃练习(活跃用户完成)。
  • @FlorisDevriendt 在您最初发表评论后,我更改了答案。 IE。我添加了一个子查询,将结果进一步过滤为仅由活跃用户完成的活跃练习。
  • @FlorisDevriendt 上述查询仅在用户完成 20 次或更多 ACTIVE 练习时才将其视为活跃用户,这正是我认为您想要的;是这样吗?
【解决方案2】:

我觉得我遗漏了一些细微差别,但在我看来,这就是我所关注的:

  • 最活跃意味着例如在 桌子。 ...
  • 我想要完成 20 次以上的练习 不同的用户。

我假设此表中没有 UserID 和 ExcerciseID 的重复项;因此,针对锻炼的用户计数是不同的,针对用户的锻炼计数是不同的。

我的方法是使用 COUNT() OVER() 来提供所需的计数,逐条记录提供,然后过滤记录。

DECLARE @cutoff int
SET @cutoff = 20

SELECT
      UserId
    , ExerciseID
    , Score
FROM (
            SELECT
                  UserId
                , ExerciseID
                , Score
                , COUNT(*) OVER (PARTITION BY UserID)     AS ExcerciseUsers
                , COUNT(*) OVER (PARTITION BY ExerciseID) AS UserExcercises
            FROM FrenchExercises
      ) AS derived
WHERE ExcerciseUsers >= @cutoff
      AND UserExcercises >= @cutoff
ORDER BY
      UserId
      , ExerciseID
;

Demo1 - small sample Demo2 - tast case by Brian DeMilia

在查看此内容时,我可能忽略了“已完成”,并假设分数为 1 表示已完成,那么以下内容会考虑到这一点:

DECLARE @cutoff int
SET @cutoff = 5

SELECT
      UserId
    , ExerciseID
    , Score
    , ExcerciseUsers
    , UserExcercises
FROM (
            SELECT
                  UserId
                , ExerciseID
                , Score
                , COUNT(*) OVER (PARTITION BY UserID)            AS ExcerciseUsers
                , COUNT(case when score = 1 then score end) OVER (PARTITION BY ExerciseID) AS UserExcercises
            FROM FrenchExercises
      ) AS derived
WHERE ExcerciseUsers >= @cutoff
      AND UserExcercises >= @cutoff
ORDER BY
      UserId
      , ExerciseID
;

Demo3 - amended sample

【讨论】:

  • 我目前无法检查您的答案,但明天会检查。至于您的假设,您在活动部分上是正确的,尽管在结果表中它应该是 20 倍或更多。至于您的第二个假设,完成的练习只是有记录的练习。分数列表示他们在该练习中的表现。只要原始表中有记录(分数列不相关),则表示用户已完成该练习。您的第三个假设是正确的,与原帖中所述没有重复。
  • 测试有什么消息吗?
  • 很抱歉,我现在很忙,恐怕我不得不推迟回答这个问题。我在做其他事情以赶上 25 日的最后期限。之后我会尝试准备一些测试数据来重现我的情况。
猜你喜欢
  • 1970-01-01
  • 2017-02-23
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多