SQL sum of previous entries - mysql

I have a table:
year val
---- ----
2013 4
2014 6
2014 2
2014 6
2015 1
2015 3
2016 7
is there a way to get the sum of the previous years for every year in the table?
the result should be like this:
2013 0
2014 4
2015 18
2016 22
2017 29
I tried something like this:
select year, sum(val) from
(select year, val from table ?????)
group by year
There should be an inner join somewhere maybe?

If you want old years only then use this query
SELECT DISTINCT year , ( SELECT SUM(val) FROM table as temp2 WHERE temp2.year < temp1.year ) as v FROM table as temp1
If you want to include year too then change temp2.year < temp1.year to <= , if you want to filter by years , then use comparison =
so
SELECT DISTINCT year , ( SELECT SUM(val) FROM table as temp2 WHERE temp2.year <= temp1.year ) as v FROM table as temp1
and
SELECT DISTINCT year , ( SELECT SUM(val) FROM table as temp2 WHERE temp2.year = temp1.year ) as v FROM table as temp1
but the latest could be easily done without subquery , just selecting year and sum(val) then group by year

Your question is a bit challenging because you want 0 for the first year:
select year,
( (#p := #p + sumval) - sumval) as cumeprev
from (select year, sum(val) as sumval
from table t
group by year
) t cross join
(select #p := 0) params
order by year;

Try
select year, #previous := #previous + sum(val)
from your_table
cross join (select #previous := 0) p
group by year
order by year

Related

mysql Fill missing month in range of two dates

I need to fill month missing in this query, and set the missing one at 0 elements :)
SELECT MONTH(timestamp), YEAR(timestamp), count(*) as Total
FROM dialogs
WHERE timestamp BETWEEN '2021-09-01' AND '2023-01-01'
GROUP BY YEAR(timestamp), MONTH(timestamp);
the result is this:
7,2022,354
8,2022,4715
9,2022,2712
10,2022,1740
but i'm expect something like:
6,2022,0 // <--- missing month in table
7,2022,354
8,2022,4715
9,2022,2712
10,2022,1740
11,2022,0 // <--- missing month in table
and so on..
you will need a full calendar
WITH recursive years AS (
select 2010 as yr
union all
select yr + 1
from years
where yr <= 2030)
, months AS (
select 1 as mon
union all
select mon + 1
from months
where mon <= 12)
SELECT cal.yr, cal.mon, ifnull(tbl.total,0) total
FROM (SELECT MONTH(timestamp) mon, YEAR(timestamp) yr, count(*) as Total
FROM dialogs
GROUP BY YEAR(timestamp), MONTH(timestamp)) tbl
right join ( select * from years join months ) cal ON cal.mon=tbl.mon and cal.yr=tbl.yr
WHERE cal.yr BETWEEN 2019 AND 2023
order by 1,2;

How to add month name with 0 total if data not exist in mysql?

I need to fetch data of the user's from created_date to till current data by month name and year with each month's total price.
Try 1:
SELECT MONTHNAME(start_time) month, YEAR(start_time) year, SUM(price) total
FROM table t1
WHERE t1.id= 33
GROUP BY YEAR(start_time), MONTH(start_time);
Output:
month year total
July 2019 360
September 2019 2160
October 2019 360
Expected output:
All month name and total will be 0 if data not exist.
month year total
Jan 2018 0
Feb 2018 0
...
Dec 2018 0
Jan 2019 0
Feb 2019 0
Mar 2019 0
Apr 2019 0
May 2019 0
Jun 2019 0
July 2019 360
Aug 2019 0
Sep 2019 2160
Oct 2019 360
Nov 2019 0
Dec 2019 0
After some RND I found one way and I have also tried that but now works.
Try 2:
SELECT IFNULL(SUM(ri.price),0) AS total, m.month
FROM (
SELECT 'Jan' AS MONTH
UNION SELECT 'Feb' AS MONTH
UNION SELECT 'Mar' AS MONTH
UNION SELECT 'Apr' AS MONTH
UNION SELECT 'May' AS MONTH
UNION SELECT 'Jun' AS MONTH
UNION SELECT 'Jul' AS MONTH
UNION SELECT 'Aug' AS MONTH
UNION SELECT 'Sep' AS MONTH
UNION SELECT 'Oct' AS MONTH
UNION SELECT 'Nov' AS MONTH
UNION SELECT 'Dec' AS MONTH
) AS m
LEFT JOIN table_u pu
ON MONTH(STR_TO_DATE(CONCAT(pu.created_date, '2019'),'%M %Y')) = MONTH(pu.created_date)
AND YEAR(pu.created_date) = '2019'
LEFT JOIN table ri
ON ri.id = pu.id
GROUP BY m.month
ORDER by 1+1;
Here is my refrence link.
Can anyone help me to fix this issue?
Thanks in advance.
Keep using LEFT JOIN (but only once) with a integer generator upto 12 (instead of month names, also easy using within the ORDER BY clause ), since you are able to get the month names by monthname() function. From your second query, I considered the current year. So, use :
SET #year=YEAR(NOW());
SELECT
MONTHNAME(STR_TO_DATE(concat(YEAR(NOW()),',',m.month,',1'),"%Y,%m,%d")) as month,
#year as year , SUM( COALESCE( pu.price, 0) ) as total
FROM (
SELECT rn as month
FROM
(
SELECT #rn := if(#i = #rn, #rn + 1, 1) as rn,
#i := #i+1
FROM information_schema.character_sets
JOIN (SELECT #i := 0, #rn := 0) as q_iter
LIMIT 12
) q
) AS m
LEFT JOIN table_u pu ON MONTH(pu.start_time) = m.month
AND YEAR(pu.start_time) = #year
AND ID = 33
GROUP BY m.month
ORDER by m.month;
Demo 1
Edit ( From the beginning of the year 2018 to the end of the current year ) :
SELECT MONTHNAME(
STR_TO_DATE(
CONCAT(m.year,',',if(mod(m.month,12)=0,12,mod(m.month,12)),',1'),"%Y,%m,%d")
)
as month,
year,
SUM( CASE WHEN YEAR(pu.start_time) = m.year AND MONTH(pu.start_time) = m.month
THEN
COALESCE( pu.price, 0)
ELSE
0
END ) as total
FROM
(
SELECT #i := if( #i = 12 , 1 , #i+1) as month,
#j := #j + 1,
#k:= if( #i = 1 and #j > 12, #k - 1, #k ) as year
FROM information_schema.character_sets
JOIN (SELECT #i := 0, #j := 0, #k:=YEAR(now())) as q_iter
) m
LEFT JOIN table_u pu ON MONTH(pu.start_time) = m.month
AND ID = 33
GROUP BY month, year
HAVING year >= ( SELECT MIN( YEAR(start_time) ) FROM table_u )
ORDER BY year, m.month;
Demo 2
If you have data in your table for all months, but just not for that id, then you can switch to conditional aggregation:
SELECT MONTHNAME(start_time) as month, YEAR(start_time) as year,
SUM(CASE WHEN t1.id = 33 THEN price ELSE 0 END) as total
FROM table t1
GROUP BY YEAR(start_time),MONTHNAME(start_time)
ORDER BY MIN(start_time);
Creating nonexistent year-month pairs by using user variables:
SELECT monthname(str_to_date(concat_ws(',',ym.month,'01,01'),'%m,%d,%y')) month
, ym.year year
, sum(price)
FROM table1 t1
RIGHT JOIN( SELECT #year := if(#month=12, #year+1, #year ) year
, #month := if(#month=12, 1 , #month+1) month
FROM table1
, ( SELECT #startYear := min(start_time)
, #endYear := year(now())
, #month := 12
, #year := min(start_time)-1
FROM table1
) t
WHERE (#year,#month) < (#endYear,12)
) ym
ON ym.year = year(t1.start_time)
AND ym.month = month(t1.start_time)
GROUP BY year(t1.start_time)
, month(t1.start_time)
The ym derived table is to provide year-month pairs starting on min year in table1 upto current year.
The innermost SELECT is for variables initialization.
You can try this:
SELECT to_char(start_time,'month')MONTH,to_char(start_time,'yyyy')YEAR,SUM(price)total
FROM TABLE_NAME
GROUP BY to_char(start_time,'month'),to_char(start_time,'yyyy')
Finally, I got the correct output which I want.
select
DATE_FORMAT(m1, '%M - %Y')
from
(
select
('2013-07-23')
+INTERVAL m MONTH as m1
from
(
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
where m1<=NOW()
order by m1

mysql row number is not working properly with order

I have a Store Database with the following tables :
1 - Provider(ProviderID,Name,Country)
2 - Product(ProductID,ProviderID,ProductPrice)
3 - Command(CommandID,ProductID,ProductQuantity,CommandDate)
I made a query that counts the gain by year
SELECT EXTRACT(YEAR FROM COMMAND_DATE) AS year,
SUM(PRODUCT_PRICE*PRODUCT_QUANTITY) AS gain
FROM PRODUCT JOIN COMMAND ON PRODUCT.PRODUCT_ID=COMMAND.PRODUCT_ID
GROUP BY year
ORDER BY year
This is the output :
Now I want to display the row number just like Oracle, so I used this query :
SET #currentRow = 0;
SELECT #currentRow := #currentRow + 1 AS counter,
EXTRACT(YEAR FROM COMMAND_DATE) AS year,
SUM(PRODUCT_PRICE*PRODUCT_QUANTITY) AS gain
FROM PRODUCT JOIN COMMAND ON PRODUCT.PRODUCT_ID=COMMAND.PRODUCT_ID
GROUP BY year
ORDER BY year
But I don't get what I want
It seems that order is affecting the row number. I want it to start from 1. Ordering by counter is not an option because I need to order by years.
This is how I want it to be :
1 2014 1863
2 2015 889
3 2016 2626
...
With group by, you need a subquery:
SELECT (#currentRow := #currentRow + 1) AS counter, y.*
FROM (SELECT EXTRACT(YEAR FROM COMMAND_DATE) AS year,
SUM(PRODUCT_PRICE*PRODUCT_QUANTITY) AS gain
FROM PRODUCT JOIN
COMMAND
ON PRODUCT.PRODUCT_ID = COMMAND.PRODUCT_ID
GROUP BY year
ORDER BY year
) y CROSS JOIN
(SELECT #currentRow := 0) params;
Or, you can use ROW_NUMBER() OVER (ORDER BY YEAR), if you are using MySQL 8+.

Select all days from a table missing some dates

I have a table with data like below, and I'm trying to sum up column b and group by day. This works great. However some days have no data in the table at all. I want to show these days as having the sum 0, but I'm a bit confused on how to get there.
Date, column b
05/24/90, 5
05/24/90, 27
05/26/90, 19
05/27/90, 24
What I want to have in the end is
05/24/90, 32
05/25/90, 0
05/25/90, 19
05/27/90, 24
etc...
Something like this should work:
DECLARE #MinDate DATE = (SELECT MIN([date]) FROM yourTable);
DECLARE #MaxDate DATE = (SELECT MAX([date]) FROM yourTable);
WITH CTE_dates
AS
(
SELECT #MinDate dates
UNION ALL
SELECT DATEADD(DAY,1,dates)
FROM CTE_dates
WHERE dates < #MaxDate
)
SELECT A.dates,
SUM(ISNULL(B.[column b],0))
FROM CTE_dates A
LEFT JOIN yourTable
ON A.dates = B.dates
GROUP BY A.dates

Getting particular day using MySql

I need to get Bth working day in a month when the value of B is entered.
For example, If b=12 in the month of January,2013 the resultant value should be in the date format as '17-01-2013' as the result is calculated
after excluding Saturdays, Sundays & holidays in the month.
I have tried it in SQLserver with the following code & its working fine, but Im finding it difficult to execute it in MySql as some functions are not
available as in Sqlserver.
Declare
#fromDate Date,
#Daydiff int
Set #fromDate ='01 jan 2013'
Set #Daydiff=datediff(day, #fromdate, dateadd(month, 1, #fromdate))
Select * from
(
Select
dateadd(day,DayNo,#fromDate) as Date,
dateName(weekday,(dateadd(day,DayNo,#fromDate))) As WeekDate,
Datename(month,(dateadd(day,DayNo,#fromDate))) as MonthName,
Row_number() Over (partition by (DatePart(month,(dateadd(day,DayNo,#fromDate))))
order by (dateadd(day,DayNo,#fromDate))) as Business_day
from
(Select top (#Daydiff) row_number() over(order by (select 1))-1 as DayNo
from sys.syscolumns a cross join sys.syscolumns b)Dates
Where
dateName(weekday,(dateadd(day,DayNo,#fromDate))) Not In ('Saturday','Sunday') and
dateadd(day,DayNo,#fromDate) Not In (Select hdate from Holidays)
)A
Where Business_day=1
Note
Holidays is the static holidays table which contains list of holidays of 2013
I need a similar instance in Mysql.
Kindly help me with this.
SQLFiddle demo
If you need first day set OFFSET 0 in the end. If the second OFFSET 1, if 15-th set OFFSET 14
select d
FROM
(
SELECT #row := #row + 1 as row,
DATE_ADD('2013-01-01', INTERVAL #row-1 DAY) d
from
(SELECT #row := 0) r,
(
select 1 n
union all
select 2 n
union all
select 3 n
union all
select 4 n
union all
select 5 n
union all
select 6 n
) t1,
(
select 1 n
union all
select 2 n
union all
select 3 n
union all
select 4 n
union all
select 5 n
union all
select 6 n
) t2
) num_seq
where
d<DATE_ADD('2013-01-01', INTERVAL 1 MONTH)
and d not in (select hdate from Holidays )
and DAYNAME(d) not in ('Saturday','Sunday')
order by d
LIMIT 1 OFFSET 20
Version without OFFSET and LIMIT. See the latest where r=1 it is the 1-st day. If you need 15-th day change to where r=15
SQLFiddle demo
select d
from
(
select d,#r := #r + 1 as r
FROM
(SELECT #r := 0) r1,
(
SELECT #row := #row + 1 as row,
DATE_ADD('2013-01-01', INTERVAL #row-1 DAY) d
from
(SELECT #row := 0) r,
(
select 1 n
union all
select 2 n
union all
select 3 n
union all
select 4 n
union all
select 5 n
union all
select 6 n
) t1,
(
select 1 n
union all
select 2 n
union all
select 3 n
union all
select 4 n
union all
select 5 n
union all
select 6 n
) t2
) num_seq
where
d<DATE_ADD('2013-01-01', INTERVAL 1 MONTH)
and d not in (select hdate from Holidays )
and DAYNAME(d) not in ('Saturday','Sunday')
order by d
) rTable
where r=1
how to get the same result when only month and year are passed as parameters. Coz when i checked the code... its working when the date is 1st of the respective month, Like if I enter parameter as '2013-01-01' the result is absolute, but if the date is given as '2013-01-15' the procedure is counting the 1st day 15th and calculating the nth day starting from there.