【问题标题】:using SUM and DISTINCT in the same query在同一查询中使用 SUM 和 DISTINCT
【发布时间】:2013-10-03 07:51:26
【问题描述】:

因此,我正在尝试构建一个查询,该查询将向我显示对于每种类型的活动,哪些用户的得分最高。您可以在下面看到表格结构。每个活动都有一个activity_typeid,每个活动都有一个特定的activity_weight

在下面的示例中,Bob 的通话得分为 50 分,会议得分为 100 分。詹姆斯在通话中得到 100 分,在会议中得到 100 分。

userid     activity_typeid     activity_weight
------------------------------------------------------------
123 (Bob)  8765 (calls)                50
123 (Bob)  8121 (meetings)             100
431 (James) 8765 (calls)               50
431 (James) 8121 (meetings)            100
431 (James) 8765 (calls)               50

我希望能够输出以下内容:

  1. 通话表现最佳 = 詹姆斯
  2. 会议表现最佳者 = Bob, James。

我事先不知道 activity_typeid,因为它们是随机输入的,所以我想知道是否可以构建某种查询来计算每个 DISTINCT/UNIQUE activity_typeid 的总和?

提前非常感谢。

【问题讨论】:

  • 为什么(James)(呼叫)在您的表中重复?
  • 对不起,我应该解释得更好。每次执行此操作(调用)时,都会在此表中输入一个新条目。因此,他的总分又增加了 50 分。所以说这不是重复的。
  • 现在看,你说,詹姆斯有 100 分的电话 = 50 + 50
  • 您能否提供此表的 SQL 代码和 SQLFiddle 上的示例数据,以便人们检查他们的答案。加上所需的输出。

标签: mysql sql


【解决方案1】:

你需要的是解析函数DENSE_RANK()。如果每个活动都需要表现最好的人,一种方法

SELECT a.activity_typeid, GROUP_CONCAT(a.userid) userid
  FROM
(
  SELECT activity_typeid, userid, SUM(activity_weight) activity_weight
    FROM table1
  -- WHERE ...
   GROUP BY userid, activity_typeid
) a JOIN 
(
  SELECT activity_typeid, MAX(activity_weight) activity_weight
    FROM
  (
    SELECT activity_typeid, userid, SUM(activity_weight) activity_weight
      FROM table1
      -- WHERE ...
     GROUP BY userid, activity_typeid
  ) q
   GROUP BY activity_typeid
) b 
    ON a.activity_typeid = b.activity_typeid
   AND a.activity_weight = b.activity_weight
 GROUP BY activity_typeid

在 MySQL 中模拟 DENSE_RANK() 的另一种方法是利用会话变量

SELECT activity_typeid, GROUP_CONCAT(userid) userid
  FROM
(
  SELECT activity_typeid, userid, activity_weight,
         @n := IF(@g = activity_typeid, IF(@v = activity_weight, @n, @n + 1) , 1) rank,
         @g := activity_typeid, @v := activity_weight
    FROM
  (
    SELECT activity_typeid, userid, 
           SUM(activity_weight) activity_weight
      FROM table1
    -- WHERE ...
     GROUP BY activity_typeid, userid
  ) q CROSS JOIN (SELECT @n := 0, @g := NULL, @v := NULL) i
     ORDER BY activity_typeid, activity_weight DESC, userid
) q
 WHERE rank = 1
 GROUP BY activity_typeid

输出:

| ACTIVITY_TYPEID |用户名 | |-----------------|---------| | 8121 | 123,431 | | 8765 |第431章

这是 SQLFiddle 两个查询的演示

【讨论】:

  • 如果我想添加 WHERE 子句,我应该在 a、b 和 c 中添加它还是只在末尾添加一次?
  • @user2656127 不客气 :) 查看更新的答案。您希望两个 WHERE 子句相同。
  • 非常感谢您的精彩回答。如果我可以再用一件事打扰你。我希望在这里运行 1 个额外的连接,主要是为了使用用户 ID 从用户表中获取用户名。我应该把它放在最后吗?此外,此代码是否适用于表中无限数量的 activity_typeid(即驱动 10 种不同类型活动的竞赛),还是仅适用于一组数字?再次感谢:D
  • @user2656127 您只需要用户名还是还需要用户 ID?
  • 好吧,我将使用 userid 加入 users 表来选择 name 和 profilepicture。
【解决方案2】:

您必须使用GROUP BY 语句来计算每个用户和每个活动类型ID 的总和。试试这样的:

SELECT userid, activity_typeid, SUM(activity_weight)
FROM table
GROUP BY userid, activity_typeid

然后将其用作子查询来确定每个 activity_typeid 的最佳执行者。

【讨论】:

【解决方案3】:

如果你想使用聚合函数,你需要使用GROUP BY,而不是DISTINCT。您可以按useridactivity_typeid 分组,然后选择SUM(activity_weight)

【讨论】:

    【解决方案4】:

    当然,只要像这样使用 group by :

    SELECT t.userid, t.activity_typeid, sum(t.activity_weight) 
    FROM YOURTABLE t
    GROUP BY t.userid, t.activity_typeid
    

    【讨论】:

      【解决方案5】:

      查询以选择给定活动的(单个)表现最佳者:

      SELECT userid, activity_typeid, SUM(activity_weight)
      FROM ?
      WHERE activity_typeid = ?
      GROUP BY userid
      ORDER BY SUM(activity_weight) DESC
      LIMIT 1
      

      您可以更改 LIMIT 以输出前 5 或 10 名表演者,然后在代码中检查它们以查看您要显示的内容(例如,如果两个人的分数相同)。

      【讨论】:

      • 谢谢!问题是 WHERE activity_typeid = ?这就是我不确定如何解决的问题,因为我不知道,并且想遍历该表中的所有 id(其中一个 id 匹配)
      • 当您知道activity_typeid 时,您知道可以在运行时构建查询吗?查找“参数化查询”以了解如何轻松完成。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多