从满足两个计数条件的表中选择行

时间:2014-08-16 17:20:00

标签: sql sql-server select count having

我有一个由用户,练习和分数组成的表格。下面可以看到表的结构和一些示例数据(只是为了给你一个想法)。

|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时,我发现结果并不完全正确。

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

2 个答案:

答案 0 :(得分:0)

根据一些评论进行编辑:

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个或更多个ACTIVE练习。他只参加了20个或更多的任何练习。这就是我改变的。

如果后者确实是你真正想要的,那么这是上一个查询:

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多个主动练习。

答案 1 :(得分:0)

我觉得我错过了一些细微差别,但对于我过于简单化的思想,这就是我所关注的:

  • 最活跃的意思是例如在20多次中出现超过20次 表。 ...
  • 我想要完成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