I am trying to get aggregate for monthly total and add extra row for yearly total into same SQL query.
Table table_1
id date amount currency
1 2017-01-01 76.89 CAD
2 2017-01-17 90.89 CAD
3 2017-01-18 65 USD
4 2017-05-13 45 CAD
5 2017-07-19 76.70 CAD
6 2018-08-13 67.34 CAD
7 2018-09-11 50 CAD
8 2018-09-09 45 CAD
9 2018-08-12 67 CAD
10 2018-07-10 55 USD
11 2018-07-11 13 USD
I have tried with this query getting total monthly and group by currency.
SELECT SUM(amount),
currency,
MONTH(date)
FROM invoices
GROUP BY MONTH(date), YEAR(date), currency
Prototype of result which I want
prototype of result
Thank you
The order you SELECT columns or ORDER them can be different from the order you GROUP them.
Then you can use GROUP BY WITH ROLLUP and check what's a super-aggregate using GROUPING() for both choosing what levels to aggregate to, and what order to display everything.
SELECT
YEAR(date),
MONTH(date),
currency,
SUM(amount)
FROM
invoices
GROUP BY
currency,
YEAR(date),
MONTH(date)
WITH
ROLLUP
HAVING
GROUPING(Currency) = 0 -- don't ROLLUP the currency
ORDER BY
GROUPING(YEAR(date)), -- individual years first, super-aggregate last
YEAR(date),
GROUPING(MONTH(date)), -- individual months first, super-aggregate last
MONTH(date),
currency
The rows for the whole years contain the NULL value in the month column
SELECT MONTH(date) AS Month,
YEAR(date) AS Year,
currency AS Currency,
SUM(amount) AS Total
FROM invoices
GROUP BY MONTH(date), YEAR(date), currency
UNION ALL
SELECT NULL, YEAR(date), currency, SUM(amount)
FROM invoices
GROUP BY YEAR(date), currency
ORDER BY Year, Month IS NULL, Month
You can find a demo here
EDIT: ordered the result set as for requirement
EDIT2: I still don't understand why the solution was not acceptable before, I tweaked it a bit to make it coincide with the new prototype of the result
Related
I have a table transactions like this
date
amount
2020-02-26
1000
2020-02-26
1500
2021-01-11
200
I want to select the sum of all transactions per month. The result should look something like...
month
sum
2020-02
2500
2021-01
200
This is what I've got so far
select sum(amount) sum, MONTH(date) month from transactions group by month;
However this groups by month ignoring year (the values returned for month are single integers). I need to group by each individual month (return a different row for Jan 2020 vs Jan 2021)
here is one way:
select sum(amount) sum, extract(YEAR_MONTH FROM `date`) month
from transactions
group by month;
I'm trying to arrange data in a table. The table has the following columns:
Customer Name, Amount, Day. The customer names are not distinct, the amount is an amount represented by dollars and the Day is over the course of 365 days.
I'm trying to arrange the amount paid per quarter, regardless of the customer name.
This is a homework assignment and I've tried this code
SELECT day as 'Quarter', SUM(amount) as 'Total Earnings'
FROM invoices
WHERE day BETWEEN 0 and 90
GROUP BY day
I'm running into 3 problems. I did the above code just to test that it would work for one quarter before i tried to tackle the whole year.
The first problem is that I need the day 'value' to be 'First' and I'm not sure how to do that at all.
Secondly, it is totaling the amounts, but not 0-90, it's totaling 1, 2, 3... 89, 90. Rather than a single row with the total 'amounts' for days 0-90.
Lastly, I'm not sure how to do another sum for the other quarters (91-180, 181-270, 271-365). I'm assuming possibly subqueries, but I'm not sure how to do that while using WHERE/BETWEEN.
My output should be something like:
Quarter | Total Earnings
-------------------------
First | 111111111
Second | 111111111
Third | 111111111
Fourth | 111111111
SELECT 'first' AS quarter, SUM(amount) AS total_earnings
FROM invoices where day between 0 AND 90
UNION ALL
SELECT 'second' AS quarter, SUM(amount) AS total_earnings
FROM invoices where day between 91 AND 180
UNION ALL
SELECT 'third' AS quarter, SUM(amount) AS total_earnings
FROM invoices where day between 181 AND 270
UNION ALL
SELECT 'fourth' AS quarter, SUM(amount) AS total_earnings
FROM invoices where day >= 271
This will get you the expected results. The group by you were using will try to group based on day unlike on quater
You could use a CASE to find what quarter a day is in and then group by that. Something like this:
SELECT `quarter` AS 'Quarter',
SUM(amount) AS 'Total Earnings'
FROM (
SELECT CASE WHEN DAY < (365/4)
THEN 'First'
WHEN t.`day` < (365/4)*2
THEN 'Second'
WHEN t.`day` < (365/4)*3
THEN 'Third'
ELSE 'Fourth'
END AS `quarter`,
t.*
FROM `table` t
) t2
GROUP BY `quarter`;
You could of course replace the 365/ whatever with just a number of days or set a variable for the number of days in a year like SET #days_in_year = 365;. I'm just manually calculating to give a quick explanation of what the number is.
With a CASE statement you can evaluate the Quarter and then you can group by Quarter:
SELECT
case
when day BETWEEN 0 and 90 then 'First'
when day BETWEEN 91 and 180 then 'Second'
when day BETWEEN 181 and 270 then 'Third'
else 'Fourth'
end Quarter,
SUM(amount) as `Total Earnings`
FROM invoices
GROUP BY Quarter
Change the day ranges as you like.
I am calculating weighted formula for a field as sum(revenue)/ Sum(qty) and this is as per the below query. Now I will be creating a view that would store these results as I shown in code below.
My question is, if I select this w_revenue out of the view and want to see per year, how will I aggregate to show it per year? See desired outputs.
select month,item, sum(revenue)/ Sum(qty) as w_revenue,
year
from my_revenue_table
group by month, year,item;
create view xyz as
select month,item, sum(revenue)/ Sum(qty) as w_revenue,
year
from my_revenue_table
group by month, year,item;
select w_revenue
from xyz.
How do I do this so as to aggregate this per year?
Year Month Item Revenue Qty Sum(revenue)/Sum(Qty)
2019 Mar A 10 2 5
2019 Mar B 30 3 10
2019 Feb C 50 1 50
2019 Feb D 20 2 10
Expected value if I see per year:
Year Sum(revenue)/Sum(Qty)
2019 13.75 (10+30+50+20)/(2+3+1+2)
group on by year then create another view as
create view abc as
select sum(revenue)/ Sum(qty) as w_revenue, year
from my_revenue_table
group by year;
and call
select * from xyz union all
select null, null, a.* from abc a
to combine them, if I understood you correctly.
or revenue per year repeating at every row as
select x.*,
(select w_revenue
from abc
where year = x.year) as w_revenue_year
from xyz x
You cannot do the aggregation you want from the view. You don't have enough information.
If you change the view to something like this:
create view xyz as
select year, month, item,
sum(revenue)/ Sum(qty) as w_revenue,
sum(qty) as total_qty
from my_revenue_table
group by month, year, item;
Then you can aggregate the results as:
select year, sum(w_revenue * total_qty) / sum(total_qty)
from xyz
group by year;
EDIT:
Or just modify the view to have the information you want:
create view xyz as
select year, month, item,
sum(revenue)/ Sum(qty) as w_revenue,
sum(qty) as total_qty,
(sum(sum(revenue)) over (partition by year, item) /
sum(sum(qty)) over (partition by year, item)
) as w_revenue_year
from my_revenue_table
group by month, year, item;
I want to create two queries for my table which has fields name,surname and amount paid,the first query should select the day,month and the amount paid,the second query should select a month,year in that year and the total amount paid in that month,lets say john paid on 2013-05-01, on 2013-05-03,while peter paid on 2013-04-08, i want the first query to output
month and day amount
05-01 200
05-03 400
04-08 50
and the second query should output:
month and year total
2013-05 600
2013-04 50
I know I can use the sum aggregate function to select the total but the tricky part is how to select the day and the month in the format above,
first query will be
SELECT DATE_FORMAT(date, "%m-%d") AS 'month and day',price as amount FROM `tablename`
and second query will be
SELECT DATE_FORMAT(date, "%Y-%m") AS 'month and year' , SUM(price) AS total FROM `tablename` GROUP BY YEAR(date), MONTH(date)
I have 2 mysql tables like bellow:
Table income Table expense
id amount date id amount date
1 200 2011-12-10 1 100 2011-12-21
2 300 2011-12-14 2 150 2012-01-01
3 500 2012-01-05 2 200 2012-01-03
I want to get data in this way:
month profit
december, 2011 400
january, 2012 150
Is this possible in a single query?
What you want is a union with some date magic for the aggregate:
select
date_format(x.date, '%M %Y') as `month`,
sum(amount) as profit
from
(select amount, date
from income
union all
select amount*-1 as amount, date
from expense
) x
group by
date_format(x.date, '%M %Y')
The specific thing we're using here is date_format to get the dates the way we want it. Also, we're multiplying amount by -1 when it comes from expense to make the calculation correct. Of course, we could have returned different columns for income and expense and then did the math on them in the sum, such as sum(x.income_amount, x.expense_amount), but there's no need to do that when you can just quickly do a *-1 to the column on before it hits the sum.
The other important thing is the group by. Here, we're grouping by a function that formats the date as Month, YYYY, so it will get the divisions you're looking for.