Show query result differently - mysql

I have this query:
SELECT pr_products.product AS PRODUCT, pr_varieties.variety AS VARIETY, pr_grades.GRADE, SUM(pf_harvest.quantity) AS QUANTITY
FROM pf_harvest
INNER JOIN pf_performance ON pf_performance.id = pf_harvest.id_performance
INNER JOIN pr_products ON pr_products.id = pf_harvest.id_product
INNER JOIN pr_varieties ON pr_varieties.id = pf_harvest.id_variety
INNER JOIN pr_grades ON pr_grades.id = pf_harvest.id_grade
WHERE pf_performance.status = 100
AND pf_harvest.id_tenant = 1
AND pf_harvest.date = '2017-03-22'
GROUP BY pf_harvest.id_product, pf_harvest.id_variety, pf_harvest.id_grade
ORDER BY pf_harvest.id_product, pr_varieties.variety, pf_harvest.id_grade;
Which shows me the following result:
-------------------------------------------------------------------
PRODUCT | VARIETY | GRADE | QUANTITY |
-------------------------------------------------------------------
ROSE | ROSEV1 | GRADE1 | 1000 |
-------------------------------------------------------------------
ROSE | ROSEV1 | GRADE2 | 5000 |
-------------------------------------------------------------------
ROSE | ROSEV2 | GRADE1 | 2000 |
-------------------------------------------------------------------
ROSE1 | ROSE1V1 | GRADE1 | 3500 |
-------------------------------------------------------------------
Is it possible to display the query result as follows?
-------------------------------------------------------------------
PRODUCT | VARIETY | GRADE1 | GRADE2 | TOTAL |
-------------------------------------------------------------------
ROSE | ROSEV1 | 1000 | 5000 | 6000 |
-------------------------------------------------------------------
ROSE | ROSEV2 | 2000 | 0 | 2000 |
-------------------------------------------------------------------
ROSE1 | ROSE1V1 | 3500 | 0 | 3500 |
-------------------------------------------------------------------
I tried to change the query but I could not and I would like to know if it is possible, I hope someone can help me.
UPDATED
NOTE: There may be more GRADES in the query result (GRADE1, GRADE2, GRADE3...).
Thanks!

Modify your current query by not grouping on the GRADE column, but instead pivot on that column. Then, use conditional aggregation to compute the GRADE1 and GRADE2 columns.
SELECT t3.product AS PRODUCT,
t4.variety AS VARIETY,
SUM(CASE WHEN t5.GRADE = 'GRADE1' THEN t1.quantity ELSE 0 END) AS GRADE1,
SUM(CASE WHEN t5.GRADE = 'GRADE2' THEN t1.quantity ELSE 0 END) AS GRADE2,
SUM(CASE WHEN t5.GRADE = 'GRADE3' THEN t1.quantity ELSE 0 END) AS GRADE3,
-- hopefully it is clear how to add more grades
SUM(t1.quantity) AS TOTAL
FROM pf_harvest t1
INNER JOIN pf_performance t2
ON t2.id = t1.id_performance
INNER JOIN pr_products t3
ON t3.id = pf_harvest.id_product
INNER JOIN pr_varieties t4
ON t4.id = t1.id_variety
INNER JOIN pr_grades t5
ON t5.id = t1.id_grade
WHERE t2.status = 100 AND
t1.id_tenant = 1 AND
t1.date = '2017-03-22'
GROUP BY t1.id_product,
t1.id_variety
ORDER BY t1.id_product,
t4.variety,
t1.id_grade;

try this
added this code
sum(case when pr_grades.Grade='Grade1' then pf_harvest.quantity else 0 end)) [Grade1],
sum(case when pr_grades.Grade='Grade2' then pf_harvest.quantity else 0 end)) [Grade2]
SELECT
pr_products.product AS PRODUCT,
pr_varieties.variety AS VARIETY,
sum(case when pr_grades.Grade='Grade1' then pf_harvest.quantity else 0 end)) [Grade1],
sum(case when pr_grades.Grade='Grade2' then pf_harvest.quantity else 0 end)) [Grade2],
SUM(pf_harvest.quantity) AS TOTAL
FROM pf_harvest
INNER JOIN pf_performance
ON pf_performance.id = pf_harvest.id_performance
INNER JOIN pr_products
ON pr_products.id = pf_harvest.id_product
INNER JOIN pr_varieties
ON pr_varieties.id = pf_harvest.id_variety
INNER JOIN pr_grades
ON pr_grades.id = pf_harvest.id_grade
WHERE pf_performance.status = 100
AND pf_harvest.id_tenant = 1
AND pf_harvest.date = '2017-03-22'
GROUP BY pf_harvest.id_product,
pf_harvest.id_variety
ORDER BY pf_harvest.id_product, pr_varieties.variety, pf_harvest.id_grade;

Related

My SUM query returns 2 rows, need some advise

I am getting 2 rows(9500) for 111 in the result, could you please advise on the right approach, I need like, Balance = (sum of bought - sum of sold)
#Table T1#
+---------+--------+------+------+
| ACCOUNT | TRANS | AMT | YEAR |
+---------+--------+------+------+
| 111 | BOUGHT | 8000 | 2019 |
| 111 | BOUGHT | 2000 | 2019 |
| 111 | SOLD | 500 | 2019 |
| 222 | BOUGHT | 6000 | 2018 |
| 222 | SOLD | 300 | 2018 |
+---------+--------+------+------+
Query
SELECT (A.BOUGHTs - B.SOLDs) AS BALANCE
FROM T1
INNER JOIN
(SELECT SUM(AMT) AS BOUGHTs
FROM T1
WHERE TRANS = 'BOUGHT'
) A
ON T1.ACCOUNT = A.ACCOUNT
INNER JOIN
(SELECT SUM(AMT) AS SOLDs
FROM T2
WHERE TRANS = 'SOLD'
) B
ON T1.ACCOUNT = B.ACCOUNT
WHERE T1.ACCOUNT = 111
AND T1.YEAR = 2019
You can use conditional aggregation:
select account, year,
sum(case when trans = 'bought' then amt
when trans = 'sold' then - amt
else 0
end) as diff
from t
group by account, year;
If you want this for only one account, you can add a where clause:
select account, year,
sum(case when trans = 'bought' then amt
when trans = 'sold' then - amt
else 0
end) as diff
from t
where account = 111 and year = 2019
group by account, year;
Rewriting your query will look like this:
SELECT (A.BOUGHTs - B.SOLDs) AS BALANCE
FROM
(SELECT ACCOUNT,YEAR,SUM(AMT) AS BOUGHTs FROM T1 WHERE TRANS = 'BOUGHT' GROUP BY ACCOUNT,YEAR) A
INNER JOIN
(SELECT ACCOUNT,YEAR,SUM(AMT) AS SOLDs FROM T1 WHERE TRANS = 'SOLD' GROUP BY ACCOUNT,YEAR) B
ON A.ACCOUNT=B.ACCOUNT AND A.YEAR=B.YEAR
WHERE A.ACCOUNT = 111
AND A.YEAR = 2019;

Complex SQL Query for Inventory System

I have 5 tables:
Items
Inventory
ConsumedItemsMonitoring
DamagedItemsMonitoring
UnaccountedItems
I'm new to Complex SQL queries did some research and asked for help and this is what I my code looks like so far.
SELECT Items.ItemID, Items.Item,
SUM(CASE WHEN DATE(Inventory.ItemTransactionDate) < CURDATE() THEN Inventory.Quantity ELSE 0 END) -
SUM(CASE WHEN DATE(consumeditemmonitoring.TransactionDate) <CURDATE() THEN consumeditemmonitoring.Quantity ELSE 0 end) -
SUM(CASE WHEN DATE(damagedinventory.ItemTransactionDate)<CURDATE() THEN damagedinventory.Quantity ELSE 0 end) -
SUM(CASE WHEN DATE(unaccounteditems.ItemTransactionDate)<CURDATE() THEN unaccounteditems.Quantity ELSE 0 end) AS 'PrevBalance',
SUM(CASE WHEN DATE(Inventory.ItemTransactionDate)=CURDATE() THEN Inventory.Quantity else 0 END) AS 'DeliveredToday',
SUM(CASE WHEN DATE(damagedinventory.ItemTransactionDate)=CURDATE() THEN damagedinventory.Quantity ELSE 0 END) AS 'DamagedToday',
SUM(CASE WHEN DATE(consumeditemmonitoring.TransactionDate)=CURDATE() THEN consumeditemmonitoring.Quantity ELSE 0 END) AS 'ConsumedToday',
SUM(CASE WHEN DATE(unaccounteditems.ItemTransactionDate)=CURDATE() THEN unaccounteditems.Quantity ELSE 0 END) AS 'UnAccountedToday',
SUM(CASE WHEN DATE(Inventory.ItemTransactionDate) < CURDATE() THEN Inventory.Quantity else 0 end)-
SUM(CASE WHEN DATE(consumeditemmonitoring.TransactionDate) < CURDATE() THEN consumeditemmonitoring.Quantity ELSE 0 END)-
SUM(CASE WHEN DATE(damagedinventory.ItemTransactionDate) < CURDATE() THEN damagedinventory.Quantity ELSE 0 END)-
SUM(CASE WHEN DATE(unaccounteditems.ItemTransactionDate) < CURDATE() THEN unaccounteditems.Quantity ELSE 0 END)-
SUM(CASE WHEN DATE(consumeditemmonitoring.TransactionDate) = CURDATE() THEN consumeditemmonitoring.Quantity ELSE 0 END)-
SUM(CASE WHEN DATE(damagedinventory.ItemTransactionDate) = CURDATE() THEN damagedinventory.Quantity ELSE 0 END)-
SUM(CASE WHEN DATE(unaccounteditems.ItemTransactionDate) = CURDATE() THEN unaccounteditems.Quantity ELSE 0 END) +
SUM(CASE WHEN DATE(Inventory.ItemTransactionDate) = CURDATE() then Inventory.Quantity ELSE 0 end) AS 'Total Balance'
FROM Items
LEFT OUTER JOIN consumeditemmonitoring ON consumeditemmonitoring.ItemID = Items.ItemID
LEFT OUTER JOIN damagedinventory ON damagedinventory.ItemID = Items.ItemID
LEFT OUTER JOIN unaccounteditems ON unaccounteditems.ItemID = Items.ItemID
LEFT OUTER JOIN inventory ON inventory.ItemID= Items.ItemID
GROUP BY Items.ItemID
The output looks like some of the table are multiplied.
What you are seeing is a result of how joins work and the fact that the joins are executed before the group by. I can illustrate this with a simplified version of your data.
drop table if exists
items,
items_inventory,
items_consumed,
items_damaged,
items_unaccounted;
create table items (id int);
create table items_inventory(id int,itemid int,qty int);
create table items_consumed(id int,itemid int,qty int);
create table items_damaged(id int,itemid int,qty int);
create table items_unaccounted(id int,itemid int,qty int);
insert into items values(1),(2);
insert into items_inventory values (1,1,10),(2,1,10),(2,2,20);
insert into items_consumed values(1,1,5),(2,2,15);
insert into items_damaged values(1,1,25);
If we run a simple select
select i.id,
ii.id,ii.qty,
ic.id,ic.qty,
id.id,id.qty,
iu.id,iu.qty
from items i
left join items_inventory ii on ii.itemid = i.id
left join items_consumed ic on ic.itemid = i.id
left join items_damaged id on id.itemid = i.id
left join items_unaccounted iu on iu.itemid = i.id
;
we get 2 rows for item 1 even though there is only 1 row for items_consumed
+------+------+------+------+------+------+------+------+------+
| id | id | qty | id | qty | id | qty | id | qty |
+------+------+------+------+------+------+------+------+------+
| 1 | 1 | 10 | 1 | 5 | 1 | 25 | NULL | NULL |
| 1 | 2 | 10 | 1 | 5 | 1 | 25 | NULL | NULL |
| 2 | 2 | 20 | 2 | 15 | NULL | NULL | NULL | NULL |
+------+------+------+------+------+------+------+------+------+
3 rows in set (0.00 sec)
When we aggregate
select i.id,
count(*) as rows,
sum(ii.qty) as inventory,
sum(ic.qty) as consumed,
sum(id.qty) as damaged,
sum(iu.qty) as unaccounted
from items i
left join items_inventory ii on ii.itemid = i.id
left join items_consumed ic on ic.itemid = i.id
left join items_damaged id on id.itemid = i.id
left join items_unaccounted iu on iu.itemid = i.id
group by i.id;
we get 'doubling' up of consumed and damaged.
+------+------+-----------+----------+---------+-------------+
| id | rows | inventory | consumed | damaged | unaccounted |
+------+------+-----------+----------+---------+-------------+
| 1 | 2 | 20 | 10 | 50 | NULL |
| 2 | 1 | 20 | 15 | NULL | NULL |
+------+------+-----------+----------+---------+-------------+
2 rows in set (0.00 sec)
One way to deal with this is to aggregate BEFORE you join by pushing the aggregations into sub queries which you would then join. For example
select i.id, ii.inventory,ic.consumed,id.damaged,iu.unaccounted,
coalesce(ii.inventory,0)+coalesce(ic.consumed,0)+coalesce(id.damaged,0)+coalesce(iu.unaccounted,0) total
from items i
left join (select ii.itemid,sum(ii.qty) as inventory from items_inventory ii group by itemid) ii on ii.itemid = i.id
left join (select ic.itemid,sum(ic.qty) as consumed from items_consumed ic group by itemid) ic on ic.itemid = i.id
left join (select id.itemid,sum(id.qty) as damaged from items_damaged id group by itemid) id on id.itemid = i.id
left join (select iu.itemid,sum(iu.qty) as unaccounted from items_unaccounted iu group by itemid) iu on iu.itemid = i.id
;
+------+-----------+----------+---------+-------------+-------+
| id | inventory | consumed | damaged | unaccounted | total |
+------+-----------+----------+---------+-------------+-------+
| 1 | 20 | 5 | 25 | NULL | 50 |
| 2 | 20 | 15 | NULL | NULL | 35 |
+------+-----------+----------+---------+-------------+-------+
2 rows in set (0.00 sec)
Working Query thanks to sir #P.Salmon
SELECT I.ItemID,
I.Item,
COALESCE(II.InventoryPrevBal,0) - COALESCE(ICP.ConsumedPrevBal,0) - COALESCE(IDP.DamagedPrevBal,0) - COALESCE(IUP.UnaccountedPrevBal,0) PrevBalance,
COALESCE(II.InventoryBal,0) CurrentDelivered,
COALESCE(IC.Consumed,0) CurrentConsumed,
COALESCE(ID.Damaged,0) CurrentDamaged,
COALESCE(IU.Unaccounted,0) CurrentUnaccounted,
COALESCE(II.InventoryPrevBal,0) + COALESCE(II.InventoryBal,0) - COALESCE(ICP.ConsumedPrevBal,0) - COALESCE(IDP.DamagedPrevBal,0) - COALESCE(IUP.UnaccountedPrevBal,0) - COALESCE(IC.Consumed,0) - COALESCE(ID.Damaged,0) - COALESCE(IU.Unaccounted,0) CurrentTotal
FROM items I
LEFT JOIN (SELECT II.ItemID, SUM(CASE WHEN DATE(II.ItemTransactionDate) < CURDATE() THEN II.Quantity ELSE 0 END) as InventoryPrevBal, SUM(CASE WHEN DATE(II.ItemTransactionDate) = CURDATE() THEN II.Quantity ELSE 0 END) as InventoryBal FROM inventory II GROUP BY ItemID) II ON II.ItemID = I.ItemID
LEFT JOIN (SELECT ICP.ItemID, ICP.TransactionDate, SUM(ICP.Quantity) as ConsumedPrevBal FROM consumeditemmonitoring ICP WHERE DATE(ICP.TransactionDate) < CURDATE() GROUP BY ItemID) ICP ON ICP.ItemID = I.ItemID
LEFT JOIN (SELECT IDP.ItemID, IDP.ItemTransactionDate, SUM(IDP.Quantity) as DamagedPrevBal FROM damagedinventory IDP WHERE DATE(IDP.ItemTransactionDate) < CURDATE() GROUP BY ItemID) IDP ON IDP.ItemID = I.ItemID
LEFT JOIN (SELECT IUP.ItemID, IUP.ItemTransactionDate, SUM(IUP.Quantity) as UnaccountedPrevBal FROM unaccounteditems IUP WHERE DATE(IUP.ItemTransactionDate) < CURDATE() GROUP BY ItemID) IUP ON IUP.ItemID = I.ItemID
LEFT JOIN (SELECT IC.ItemID, IC.TransactionDate, SUM(IC.Quantity) as Consumed FROM consumeditemmonitoring IC WHERE DATE(IC.TransactionDate) = CURDATE() GROUP BY ItemID) IC ON IC.ItemID = I.ItemID
LEFT JOIN (SELECT ID.ItemID, ID.ItemTransactionDate, SUM(ID.Quantity) as Damaged FROM damagedinventory ID WHERE DATE(ID.ItemTransactionDate) = CURDATE() GROUP BY ItemID) ID ON ID.ItemID = I.ItemID
LEFT JOIN (SELECT IU.ItemID, IU.ItemTransactionDate, SUM(IU.Quantity) as Unaccounted FROM unaccounteditems IU WHERE DATE(IU.ItemTransactionDate) = CURDATE() GROUP BY ItemID) IU ON IU.ItemID = I.ItemID
ORDER BY I.Item ASC

MySQL CASE ELSE not returning 0 in multi join select statement

I have a view like this:
VIEW `my_view` AS (
SELECT
t1.sku AS sku,
FORMAT(SUM((CASE
WHEN (t3.order_date > (CURDATE() - INTERVAL 42 DAY)) THEN t2.qty
ELSE 0
END)),
0) AS qty_sold,
FORMAT(SUM((CASE
WHEN (t3.order_status_id = 3) THEN t2.qty
ELSE 0
END)),
0) AS qty_ordered
FROM
inventory_products t1
JOIN inventory_sales t2 ON (t2.sku = t1.sku)
JOIN inventory_orders t3 ON (t3.id = t2.order_id)
where t1.sku=1001 or t1.sku=1002 or t1.sku=1010
GROUP BY t1.sku
)
The view works as expected, and returns correct results, except that when a sku doesn't exist on the inventory_sales table, the row for that sku doesn't return at all.
Note that the sku=1010 doesn't exist on the inventory_sales table, but it does exist on the inventory_products table.
for example:
SELECT * FROM my_view
WHERE sku=1001 OR sku=1002 OR sku=1010
returns this:
+-----------+--------------+------------+
| sku | qty_sold |qty_ordered |
+-----------+--------------+------------+
| 1001 | 2 | 2 |
+-----------+--------------+------------+
| 1002 | 3 | 3 |
+-----------+--------------+------------+
but I need it to return this:
+-----------+--------------+------------+
| sku | qty_sold |qty_ordered |
+-----------+--------------+------------+
| 1001 | 2 | 2 |
+-----------+--------------+------------+
| 1002 | 3 | 3 |
+-----------+--------------+------------+
| 1010 | 0 | 0 |
+-----------+--------------+------------+
What am I missing here? Any advice would be appreciated :)
I think you just need left join:
SELECT . . .
FROM inventory_products t1 LEFT JOIN
inventory_sales t2
ON t2.sku = t1.sku LEFT JOIN
inventory_orders t3
ON t3.id = t2.order_id
WHERE t1.sku IN (1001, 1002, 1010)
GROUP BY t1.sku
I think the ELSE 0 will turn the NULL into a 0 -- your desired result.

Why the sum value from mysql_fetch was double up?

I have an 2 database.
1 is game_jnship_user, 2 is game_jnship_equip and the data as below:
Here is game_jnship_user
+-----+-----------------+
| ID | uid |
+-----+-----------------+
| 1 | 50 |
+-----------------------+
Here is game_jnship_equip
+-----+------------+---------------+--------------+
| ID | uid | ebonus | etype |
+-----+------------+---------------+--------------+
| 1 | 50 | 100 | 1 |
| 2 | 50 | 10 | 1 |
| 3 | 50 | 120 | 2 |
+-------------------------------------------------+
And I query as below:
$_G['uid'] = '50';
$ushuxing = DB::query("SELECT sum(t2.ebonus) AS equipatk, sum(t3.ebonus) AS equipdef FROM ".DB::table('game_jnship_user')." t1 LEFT JOIN ".DB::table('game_jnship_equip')." t2 ON (t1.uid = t2.uid AND t2.etype = '1') LEFT JOIN ".DB::table('game_jnship_equip')." t3 ON (t1.uid = t3.uid AND t3.etype = '2') WHERE t1.uid = $_G[uid]");
$rushuxing = DB::fetch($ushuxing);
After that, my output data as below:
$rushuxing[equipatk] = 110;
$rushuxing[equipdef] = 240;
Why the $rushuxing[equipdef] output is 240 not 120?
Thank you.
Here is the raw MySQL query from the example above:
SELECT sum(t2.ebonus) AS equipatk, sum(t3.ebonus) AS equipdef
FROM game_jnship_user t1
LEFT JOIN game_jnship_equip t2
ON (t1.uid = t2.uid AND t2.etype = '1')
LEFT JOIN game_jnship_equip t3
ON (t1.uid = t3.uid AND t3.etype = '2')
WHERE t1.uid = '50'
The record having etype = 2 is matched with 2 records having etype = 1 in the LEFT JOIN operation, so you get 240 instead of 120.
You can use instead the following query that makes use of conditional aggregation:
SELECT SUM(CASE WHEN etype = 1 THEN ebonus ELSE 0 END) AS equipatk,
SUM(CASE WHEN etype = 2 THEN ebonus ELSE 0 END) AS equipdef
FROM game_jnship_equip
WHERE uid = 50
GROUP BY uid clause is not required since you are performing aggregation for a specific uid value.

sum two rows and order by date / total

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