总和两行,按日期/总数排序

时间:2013-10-25 21:52:20

标签: mysql sql gaps-and-islands

需要一些帮助来构建查询,这是我目前的方案:

users:
+----+------------+
| id |  username  |
+----+------------+
| 1  |    rob     |
| 2  |    john    |
| 3  |    jane    | <--- jane never has donated
| 4  |    mike    | 
+----+------------+

donations:
+--------------------+------------+
|   uid   |  amount  |   date     |
+---------+----------+------------+
|    1    |    20    | 2013-10-10 | 
|    2    |    5     | 2013-10-03 | 
|    2    |    50    | 2013-09-25 |
|    2    |    5     | 2013-10-01 |
|    4    |    100   | 2012-10-01 | <-- past year
+---------+----------+------------+


Result I want:
+---------+-------------+---------+-------------+---------------+----------+ 
|    id   |   username  | amount  |   monthly   |  totalamount  |   total  |
+---------+-------------+---------+-------------+ --------------+----------+
|    1    |     rob     |   20    |      1      |       20      |     1    |
|    2    |     john    |   60    |      3      |       60      |     3    |
|    3    |     jane    |   0     |      0      |       0       |     0    |
|    4    |     mike    |   0     |      0      |       100     |     1    | 
+---------+-------------+-----------------------+---------------+----------+

这是我的疑问:

SELECT
  u.*,
  COALESCE(sum(d.amount), 0) amount,
  COUNT(d.uid) monthly, 
  COUNT(d.amount) as Total, <-- need to get sum all time donations and number of times donated
FROM users u
LEFT JOIN donations d
  ON u.id = d.uid
    AND (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE()))
GROUP BY u.id ORDER BY u.id ASC

所以我需要从相同的数据中添加2个不同的总和。

编辑:http://sqlfiddle.com/#!2/20a974/9架构和数据

我怎么能这样做?

3 个答案:

答案 0 :(得分:2)

为此,我们需要过滤选择而不是连接上的数据。

删除此条件:

AND (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE()))

并将其添加到选择:

SUM (CASE WHEN (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE())) THEN 1 ELSE 0 END) as monthly

编辑:

整个查询:

SELECT users.id, users.username, 
  COALESCE(sum(CASE WHEN (month(donations.date), year(donations.date)) = (month(CURDATE()), year(CURDATE())) THEN donations.amount ELSE 0 END), 0) monthly_sum, 
  COALESCE(sum(CASE WHEN (month(donations.date), year(donations.date)) = (month(CURDATE()), year(CURDATE())) THEN 1 ELSE 0 END), 0) monthly_amount, 

  COALESCE(sum(donations.amount), 0) total_sum, 
  count(*) total_amount

from users
left join donations
  on donations.uid = users.id
group by users.id, users.username

http://sqlfiddle.com/#!2/20a974/20/0

答案 1 :(得分:1)

对我来说,考虑单独分组信息的最简单方法是将其放入单独的查询中,然后将结果重新加入。这可能不是最有效的,但它有助于让事情有效。

select auo.id, auo.username, 
  coalesce(monthly_count, 0), coalesce(monthly_total, 0),
  coalesce(total, 0), coalesce(total_amount, 0)
from aaa_users auo
left join  (
   select au.id as id, count(adm.amount) as monthly_count, SUM(adm.amount) as monthly_total
   from aaa_users au join aaa_donations adm on au.id = adm.uid and adm.donate_date > GETDATE()-30
   group by au.id
) as monthly on monthly.id = auo.id
left join (
   select au.id as id, count(ady.amount) total, SUM(ady.amount) as total_amount
   from aaa_users au join aaa_donations ady on au.id = ady.uid and ady.donate_date >  getDate()-450
   group by au.id 
) as yearly on yearly.id = auo.id

正如@CompuChip所说,加入捐赠表两次更加清晰,但是我的连接逻辑出了问题,因为john的值正在重复。我认为需要有一个捐赠专栏,以防止每月和全部捐款被合并。无论如何,这是一个例子,即使它不能正常工作

select au.id, au.username, 
    count(adm.amount), SUM(adm.amount) as monthly_total, 
    count(ady.amount), SUM(ady.amount) as total_amount
from aaa_users au 
left outer join aaa_donations adm on au.id = adm.uid and adm.donate_date > GETDATE()-60
left outer join aaa_donations ady on au.id = ady.uid and ady.donate_date > getDate()-450
group by au.id, au.username
order by au.id, au.username

答案 2 :(得分:0)

你可以再做一次捐赠,给它一个不同的别名:在d2.uid = u.id上LEFT JOIN捐款d2。然后对最后两个字段的d2.amount求和,例如

SELECT u.*, 
  COALESCE(sum(d.amount), 0) amount, 
  COUNT(d.uid) monthly, 
  COUNT(d.amount) as Total, 

  COALESCE(sum(d2.amount), 0) amountAll, 
  COUNT(d2.uid) monthlyAll,
  COUNT(d2.amount) as TotalAll

  FROM users u
     LEFT JOIN donations d ON u.id = d.uid AND (month(d.date), year(d.date)) = (month(CURDATE()), year(CURDATE()))
     LEFT JOIN donations d2 ON u.id = d2.uid 

 GROUP BY u.id ORDER BY u.id ASC