sum two rows and order by date / total

痞子三分冷 提交于 2019-12-25 01:46:18

问题


need some help to build a query, this is my current scheme:

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    | 
+---------+-------------+-----------------------+---------------+----------+

This is my query:

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

So i need to add 2 different sums from same data.

EDIT: http://sqlfiddle.com/#!2/20a974/9 schema and data

How I can do this?


回答1:


For this we need to filter the data on the select and not on the join.

Remove this condition:

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

and add this to the select:

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

Edit:

whole query:

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




回答2:


For me the easiest way to think about the separately grouped information is to put it into separate queries and then just join the results back together. This is not likely to be the most efficient, but it helps to get something working.

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

As @CompuChip said, it's cleaner to just join to the donations table twice, but I have something wrong in my join logic as the values for john are getting duplicated. I think there would need to be a donations.id column to prevent the monthly and total donations from being combined. Anyway, here's an example even though it isn't working correctly

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



回答3:


You can do another join to donations, giving it a different alias: LEFT JOIN donations d2 on d2.uid = u.id. Then sum over d2.amount for the last two fields, e.g.

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


来源:https://stackoverflow.com/questions/19600003/sum-two-rows-and-order-by-date-total

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!