5

我无法根据另一个字段值对字段值求和

我需要SUM(activities.points)根据activities.activity_type它是used_pointsoradded_points并将其放入AS used_points/added_points.

活动

id | subscription_id  | activity_type | points
--------------------------------------------------
1  |         1        |  used_points  |   10
2  |         1        |  used_points  |   50 
3  |         1        | added_points  |   20 
4  |         1        | added_points  |   30
5  |         2        |  used_points  |   20
6  |         2        |  used_points  |   45
7  |         2        | added_points  |   45
8  |         2        | added_points  |   45

订阅

id |     name    |  current_points
-------------------------------------
 1 |    card_1   |        700
 2 |    card_2   |        900

我需要的:

  name   |  current_points  | used_points | added_points
-----------------------------------------------------------
 card_1  |         700      |     60      |     50
 card_2  |         900      |     65      |     90

我尝试了什么:

SELECT
    subscriptions.name,
    subscriptions.current_points,
    IF(activities.activity_type="used_points", SUM(activities.points), null)
        AS used_points,
    IF(activities.activity_type="added_points", SUM(activities.points), null)
        AS added_points 
FROM activities
JOIN subscriptions
    ON activities.subscription.id = subscription.id
GROUP BY subscriptions.name

这是错误的。

谢谢

4

4 回答 4

6

你想用SUM(IF( )). 您想要将从IF. 您希望IF为每个单独的行评估该表达式。然后,使用SUM聚合将每行返回的值相加。

从表达式内部删除SUM聚合IF,而是将IF内部包装为SUM.


跟进

但是为什么 IF 内部的 SUM() 不起作用?

嗯,它确实有效它只是没有按照您希望的方式工作。

MySQLSUM函数是一个“聚合”函数。它将行聚合在一起,并返回一个值。

对于这种形式的表达式: IF(col='foo',SUM(numcol),0)

MySQL 所做的是将所有行聚合到 SUM 中,并返回一个值。

col其他数据库会很合适,并在该表达式中引用非聚合时抛出错误。MySQL 更宽松,并将col引用视为聚合(如 MIN(col) 或 MAX(col)... 处理一组行,并返回单个值。在这种情况下,MySQL 正在选择一个单,样本行。(不确定哪一行将被“选择”为样本行。)所以这个引用col有点像一个GET_VALUE_FROM_SAMPLE_ROW(col)。一旦聚合完成,那么该 IF 表达式将被评估一次。

如果您从这个查询开始,这是您要操作的行集。

SELECT s.name
     , s.current_points
     , a.activity_type
     , a.points
     , IF(a.activity_type='used_points',a.points,NULL) AS used_points
     , IF(a.activity_type='added_points',a.points,NULL) AS added_points
  FROM subscriptions s
  JOIN activities a
    ON a.subscription_id = s.id

当您添加 GROUP BY 子句时,这会将其中一些行聚合在一起。对于非聚合,您将获得来自样本行的值。

尝试添加GROUP BY s.name到查询中,看看返回了什么。

还可以尝试添加一些聚合,例如 SUM(a.points)

SELECT s.name
     , s.current_points
     , a.activity_type
     , a.points
     , IF(a.activity_type='used_points',a.points,NULL) AS used_points
     , IF(a.activity_type='added_points',a.points,NULL) AS added_points
     , SUM(a.points) AS total_points
  FROM subscriptions s
  JOIN activities a
    ON a.subscription_id = s.id
 GROUP BY s.name

最后,我们可以将查询中的表达式添加到 SELECT 列表中:

     , IF(a.activty_type='used_points',SUM(a.points),NULL) AS if_used_sum
     , IF(a.activty_type='added_points',SUM(a.points),NULL) AS if_added_sum

我们发现从这些表达式返回的值要么是 SUM(a.points),它与 ​​匹配total_points,要么是 NULL。我们可以看到activity_type从每个组的单个样本行中检索到的列的值,我们可以看到这个表达式正在“工作”,它只是没有做我们真正想要发生的事情:对于条件测试在每个单独的行上运行,返回一个点值或空值,然后为组求和。

于 2013-08-13T15:47:14.640 回答
2

您的代码只是稍微有点:

SELECT
    subscriptions.name,
    subscriptions.current_points,
    SUM(IF(activities.activity_type="used_points", 0, activities.points))
        AS used_points,
    SUM(IF(activities.activity_type="added_points", 0, activities.points))
        AS added_points 
FROM activities
JOIN subscriptions
    ON activities.subscription_id = subscription.id
GROUP BY subscriptions.name, subscriptions.current_points

请注意倒数第二行中的固定错字 - 您编写的是 subscription.id 而不是 subscription_id。此外,您只按名称而不是名称和 current_points 进行分组,不确定 mysql 中是否允许这样做(我使用 T-SQL),无论如何最好将它放在那里。

于 2013-08-13T15:55:40.727 回答
2

好吧,我没有使用 IF 语句。这是示例(http://sqlfiddle.com/#!2/076c3f/12):

SELECT
    subs.name,
    subs.current_points,
    (SELECT SUM(points) FROM activities WHERE type = 1 AND subs_id = subs.id) AS used_points,
    (SELECT SUM(points) FROM activities WHERE type = 2 AND subs_id = subs.id) AS added_points
FROM activities
JOIN subs ON activities.id = subs.id
GROUP BY subs.name

注意:我将类型从 VARCHAR 更改为 INT 以简化。

于 2013-08-13T15:58:14.620 回答
1

尝试改变

IF(activities.activity_type="used_points", null, SUM(activities.points))
    AS used_points,
IF(activities.activity_type="added_points", null, SUM(activities.points))
    AS added_points 

到下一个

SUM(IF(activities.activity_type="used_points", activities.points, 0))
    AS used_points,
SUM(IF(activities.activity_type="added_points", activities.points, 0))
    AS added_points 

通过这种方式,您检查列和总和点或 0

于 2013-08-13T15:39:52.930 回答