根据另一列值求和列

时间:2013-08-13 15:35:40

标签: mysql sql

我遇到求和字段值基于其他字段值的问题。

如果是SUM(activities.points)activities.activity_type,我需要used_points基于added_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 个答案:

答案 0 :(得分:3)

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

SUM表达式中删除IF聚合,然后将IF包裹在SUM内。


<强>跟进

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

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

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

对于此表单的表达式: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列的值,从每个组的单个样本行中检索,我们可以看到这是表达式“正在工作”,它只是没有做我们你真正想要发生的事情:对于在每个单独的行上运行的条件测试,返回points或null的值,然后将该值汇总为该组。

答案 1 :(得分: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

答案 2 :(得分:1)

您的代码只是略有出现:

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。你也只按名称而不是name和current_points分组,不确定mysql中是否允许(我使用T-SQL),最好还是把它放在那里。

答案 3 :(得分:1)

好吧,我没有使用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以简化。