我遇到求和字段值基于其他字段值的问题。
如果是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
哪个错了。
由于
答案 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以简化。