MySQL monthly sums - mysql

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;

Related

SQL aggregate get monthly and yearly

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

how to find the first and last records of every month in mysql database

I want to fetch the first and last record of every month in sql but my query give the results below and here is my query
SELECT DISTINCT month, amount,
MIN(date) OVER (PARTITION BY month ORDER BY utility.month)
FROM
utility;
results of the query above
month
amount
min(date)
February/2022
200
2022-02-02
January/2022
1000
2022-01-01
January/2022
200
2022-01-01
March/2022
1000
2022-02-06
You can get the MIN() and MAX() value first, turn into a subquery then join utility table twice to get the amount corresponding to the extracted dates, like this:
SELECT v.month,
v.mindt,
u1.amount,
v.maxdt,
u2.amount
FROM
(SELECT month,
MIN(date) mindt, MAX(date) maxdt
FROM
utility
GROUP BY month) v
JOIN utility u1 ON u1.date=v.mindt
JOIN utility u2 ON u2.date=v.maxdt
;
That will give result something like this:
month
mindt
amount
maxdt
amount
January2022
2022-01-02
250
2022-01-29
350
February2022
2022-02-01
300
2022-02-28
500
March2022
2022-03-03
500
2022-03-18
300
Or you can modify the subquery to do UNION ALL, join utility once and return all in just the original 3 columns:
SELECT v.month,
v.minmaxdt,
u.amount
FROM
(SELECT month,
MIN(date) minmaxdt
FROM utility
GROUP BY month
UNION ALL
SELECT month,
MAX(date)
FROM utility
GROUP BY month
) v
JOIN utility u ON u.date=v.minmaxdt
ORDER BY v.month, v.minmaxdt;
That will give result something like this:
month
minmaxdt
amount
February2022
2022-02-01
300
February2022
2022-02-28
500
January2022
2022-01-02
250
January2022
2022-01-29
350
March2022
2022-03-03
500
March2022
2022-03-18
300
Demo fiddle
Try using MIN and MAX at the same time together with GROUP BY.
Check this from W3Schools.
The MIN() function returns the smallest value of the selected column.
The MAX() function returns the largest value of the selected column.
Try this code:
SELECT DISTINCT month, amount, MIN(date), MAX(date) FROM utility GROUP BY month;

Calculating points from number of days worked in a week/month by each employee

I am trying to calculate the average points for employees for a period of a week (or calendar month if possible) from a range of records. I have a table: daily_schedule which has records like this
I have tried the query:
SELECT WEEK(date)
,employeeid
,AVG(points)
FROM `daily_schedule`
GROUP BY WEEK(date), employeeid
But that is calculating the average on jobs rather than the date per employee
The result I want to achieve is
Is there any way to achieve the average by week and/or calendar month?
Thank you in advance.#
The WEEK(date) function will give you the number of week in the year from that date. And if you want to achieve what you've mentioned here, you can simply group by WEEK(date) and then employeeid. You can execute a CTE in this purpose. Then select the aggregated grouped values from CTE and AVG from points/days collected from cte.
So you can execute:
with cte as (select employeeid, sum(points) as points, count(distinct date_val) as days, WEEK(DATE_VAL) as week_no
from daily_schedule ds group by WEEK(date_val), employeeid)
select week_no, employeeid, points, days, points/days as avg from cte;
From the week no, you can identify which week of the year this is.
This will give you the expected output.
Output of this query is:
week_no
employeeid
points
days
avg
26
113877
4.5
2
2.25
26
122396
4.2
2
2.1
26
124514
3.7
1
3.7
27
113877
1.8
1
1.8
27
122396
1.2
1
1.2
27
124514
1.6
1
1.6

selecting the month day and year from a transaction table

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)

mysql select data with calculation between 2 tables and group by month

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.