Can Any one please tell me how to add one whole month date's in mysql database. For now I'm adding one date at a time.
This query generates all the days of a given month.
I found this in this post.
When you change NOW() function with any date you want, it generates the dates of that month. You can also join this with your queries or you can use it with INSERT [(col_name,...)] SELECT ... statement to insert all the dates to a table.
SELECT date_field
FROM
(
SELECT
MAKEDATE(YEAR(NOW()),1) +
INTERVAL (MONTH(NOW())-1) MONTH +
INTERVAL daynum DAY date_field
FROM
(
SELECT t*10+u daynum
FROM
(SELECT 0 t UNION SELECT 1 UNION SELECT 2 UNION SELECT 3) A,
(SELECT 0 u UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9) B
ORDER BY daynum
) AA
) AAA
WHERE MONTH(date_field) = MONTH(NOW());
plan
build up decimal numbers with cross join on digits - all numbers can be expressed as :
an10^n + .. a0*10^0
use date_add to add start of month data filtering where less than next month start
setup
create table example
(
`date` date primary key not null
);
drop view if exists digits_v;
create view digits_v
as
select 0 as n
union all
select 1 union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6 union all
select 7 union all select 8 union all select 9
;
query
insert into example ( `date` )
select date_add(date('2015-11-01'), interval a2.n * 100 + a1.n * 10 + a0.n day)
from digits_v a2
cross join digits_v a1
cross join digits_v a0
where date_add(date('2015-11-01'), interval a2.n * 100 + a1.n * 10 + a0.n day)
< date('2015-12-01')
;
sqlfiddle
selecting the top 10 gives
select `date`
from example
order by `date`
limit 10
;
.
+----------------------------+
| date |
+----------------------------+
| November, 01 2015 00:00:00 |
| November, 02 2015 00:00:00 |
| November, 03 2015 00:00:00 |
| November, 04 2015 00:00:00 |
| November, 05 2015 00:00:00 |
| November, 06 2015 00:00:00 |
| November, 07 2015 00:00:00 |
| November, 08 2015 00:00:00 |
| November, 09 2015 00:00:00 |
| November, 10 2015 00:00:00 |
+----------------------------+
Related
I have the following stored procedure get the last 12 months from the current date in MySql
DELIMITER $$
CREATE
PROCEDURE `Calendar`()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS `Cal` (
`month` INT(11) ,
`year` INT(11)
);
TRUNCATE TABLE Cal;
SET #counter := -1;
WHILE (DATEDIFF(DATE(NOW()), DATE(DATE_SUB(NOW(),INTERVAL #counter MONTH))) < DATEDIFF(DATE(NOW()), DATE(DATE_SUB(NOW(),INTERVAL 12 MONTH)))) DO
INSERT INTO Cal SELECT DATE_FORMAT(DATE_ADD(DATE_SUB(NOW(),INTERVAL 12 MONTH), INTERVAL #counter:=#counter + 1 MONTH),'%m'),DATE_FORMAT(DATE_ADD(DATE_SUB(NOW(),INTERVAL 12 MONTH), INTERVAL #counter + 1 MONTH),'%Y');
END WHILE;
SELECT * FROM `Cal`;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS Calendar;
The output table is
9 2017
10 2017
11 2017
12 2018
1 2018
2 2018
3 2018
4 2018
5 2018
6 2018
7 2018
8 2018
9 2018
In the month 12, the year is 2018. It should be 2017 and also the row 9 2017 shouldn't be there since its the 13th month including the current month. How can I make the 12th month's year to 2017 and remove the 9 2017 Thanks in advance
Here's a stored procedure that will give you the output you desire. It's longer but simpler than what you were attempting.
DELIMITER //
DROP PROCEDURE IF EXISTS Calendar //
CREATE PROCEDURE Calendar ()
BEGIN
DECLARE month INT DEFAULT MONTH(CURDATE());
DECLARE year INT DEFAULT YEAR(CURDATE()) - 1;
CREATE TEMPORARY TABLE CAL (month INT, year INT);
REPEAT
SET month = month + 1;
IF (month = 13) THEN
SET month = 1;
SET year = year + 1;
END IF;
INSERT INTO CAL VALUES (month, year);
UNTIL month = MONTH(CURDATE())
END REPEAT;
SELECT * FROM CAL;
DROP TABLE CAL;
END //
DELIMITER ;
CALL Calendar();
Output:
month year
10 2017
11 2017
12 2017
1 2018
2 2018
3 2018
4 2018
5 2018
6 2018
7 2018
8 2018
9 2018
You can also do it without a creating a stored procedure, temporary table, inserting into temporary table and dropping the stored procedure after
By using a number generator in MySQL code.
Query
SELECT
MONTH(NOW() - INTERVAL number_generator.number MONTH) AS `month`
, YEAR(NOW() - INTERVAL number_generator.number MONTH) AS `year`
FROM (
SELECT
(#NUMBER := #NUMBER + 1) AS number
FROM (
SELECT 1 AS number UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS records_1
CROSS JOIN (
SELECT 1 AS number UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS records_2
CROSS JOIN (SELECT #NUMBER := 0) AS init_user_params
) AS number_generator
WHERE
number_generator.number BETWEEN 1 AND 12
AND
MONTH(NOW()) <> MONTH(NOW() - INTERVAL number_generator.number MONTH)
ORDER BY
YEAR(NOW() - INTERVAL number_generator.number MONTH) ASC
, MONTH(NOW() - INTERVAL number_generator.number MONTH) ASC
Results
| month | year |
|-------|------|
| 10 | 2017 |
| 11 | 2017 |
| 12 | 2017 |
| 1 | 2018 |
| 2 | 2018 |
| 3 | 2018 |
| 4 | 2018 |
| 5 | 2018 |
| 6 | 2018 |
| 7 | 2018 |
| 8 | 2018 |
see demo http://sqlfiddle.com/#!9/340e01/584
Note if you use MySQL 8.0+ the syntax is more clear using common table expressions.
Query
WITH RECURSIVE number_generator (number) AS
(
SELECT 1 AS number
UNION ALL
SELECT number + 1 FROM number_generator WHERE number < 12
)
SELECT
MONTH(NOW() - INTERVAL number_generator.number MONTH) AS `month`
, YEAR(NOW() - INTERVAL number_generator.number MONTH) AS `year`
FROM
number_generator
WHERE
MONTH(NOW()) <> MONTH(NOW() - INTERVAL number_generator.number MONTH)
ORDER BY
YEAR(NOW() - INTERVAL number_generator.number MONTH) ASC
, MONTH(NOW() - INTERVAL number_generator.number MONTH) ASC
Results
| month | year |
|-------|------|
| 10 | 2017 |
| 11 | 2017 |
| 12 | 2017 |
| 1 | 2018 |
| 2 | 2018 |
| 3 | 2018 |
| 4 | 2018 |
| 5 | 2018 |
| 6 | 2018 |
| 7 | 2018 |
| 8 | 2018 |
see demo https://www.db-fiddle.com/f/chJ4qS2ocXS79vGkFBg7PR/13
I have a database in which i have a table to save reports . Each report haves a date (year-month-day) which is set whenever the report got created .
After a lot of tests i got something to work but just not as i would like it to work.
I want to get the quantity of reports that were made on every month from an initial date (year-month-day) to a final date (year-month-day). But i'm not quite sure how to get it done.
This is the MySQL sentence i'm using right now:
SELECT meses.month id_mes, count(re_fecha) total
FROM
(
SELECT 1 AS MONTH
UNION SELECT 2 AS MONTH
UNION SELECT 3 AS MONTH
UNION SELECT 4 AS MONTH
UNION SELECT 5 AS MONTH
UNION SELECT 6 AS MONTH
UNION SELECT 7 AS MONTH
UNION SELECT 8 AS MONTH
UNION SELECT 9 AS MONTH
UNION SELECT 10 AS MONTH
UNION SELECT 11 AS MONTH
UNION SELECT 12 AS MONTH
) as meses
LEFT JOIN reportes ON month(re_fecha) = meses.MONTH
WHERE re_fecha BETWEEN '2017-01-01' AND '2017-08-31'
GROUP BY meses.MONTH, monthName(re_fecha)
This is the following result i'm getting with the MySQL sentence:
id_mes | total
---------------
04 | 15
05 | 5
06 | 15
07 | 2
I'm not sure if this helps in any way, but if i don't use the "where re_fechas... " i get a result that is closer to what we look for:
id_mes | total
-------------
01 | 0
02 | 0
03 | 0
04 | 15
05 | 5
06 | 15
07 | 2
08 | 6
09 | 0
10 | 0
11 | 0
12 | 0
And finally, what i would like to see:
id_mes | total
-------------------
01-2017 | 0
02-2017 | 0
03-2017 | 0
04-2017 | 15
05-2017 | 5
06-2017 | 15
07-2017 | 2
08-2017 | 6
I have two problems with how it works now:
When i use the sentence "where" the months that have 0 reports on the specified dates, are not shown. If i do not use "where", i get the things almost in the way i want them, but not in the range of dates i want.
The other issue i had is i would like to get the year of the month (As shown in the desired code block above).
I hope this is enough information to understand everything, i'm not sure if i could provide the database, but if you think that would help, let me know.
You almost got it.
If you add OR re_fecha IS NULL to your WHERE clause, then you would got almost what you wanted.
I came up with another solution that can help you:
SELECT meses.aMonth aMonth, COUNT(re_fecha) total
FROM (
-- Listing all months in period
SELECT DATE_FORMAT(m1, '%m-%Y') aMonth
FROM (
-- Range limit: about 21 years
SELECT
('2017-01-01' - INTERVAL DAYOFMONTH('2017-01-01')-1 DAY) +INTERVAL m MONTH as m1
FROM (
SELECT #rownum:=#rownum+1 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 <= '2017-08-31'
ORDER BY m1) meses
LEFT JOIN reportes ON DATE_FORMAT(re_fecha, '%m-%Y') = meses.aMonth
WHERE re_fecha BETWEEN '2017-01-01' AND '2017-08-31'
OR re_fecha IS NULL
GROUP BY meses.aMonth;
Test it: http://sqlfiddle.com/#!9/d21de6/27
Example output:
aMonth total
01-2017 0
02-2017 0
03-2017 0
04-2017 15
05-2017 5
06-2017 0
07-2017 2
08-2017 0
If you wasn't using MySQL, then you could use a FULL OUTER JOIN instead of LEFT JOIN.
Keep in mind that this solution is limited to 21 years. Try it changing only the initial date to 1970 and see it for yourself.
If needed, add more (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) tn, to increase the number of months.
References and useful links:
MySQL monthly Sale of last 12 months including months with no Sale
How to get a list of months between two dates in mysql
How to do a FULL OUTER JOIN in MySQL?
In your query try to change WHERE to AND.
What query to get all the Sundays date between January - March 2016?
so output just the shown date only.
| Sundays |
|- - - - - -|
| 2 |
| 9 |
| 16 |
| 23 |
| 30 |
- - - - - -
i find query like this select ('2013-04-15' - interval dayofweek('2013-08-15') - 1 day) - interval (weekofyear('2013-04-15') - 1) * 7 day as SUNDAY;
but just shown one sunday.
To get the Sunday below query will work for you
select DATE_ADD('2016-01-01', INTERVAL ROW DAY) as Date,
row+1 as DayOfMonth
from
(
SELECT #row := #row + 1 as row
FROM
(
select 0
union all
select 1
union all
select 3
union all
select 4
union all
select 5
union all
select 6
) t1,
(
select 0
union all
select 1
union all
select 3
union all
select 4
union all
select 5
union all
select 6
) t2,
(SELECT #row:=-1
) t3 limit 31
) b
where
DATE_ADD('2016-01-01', INTERVAL ROW DAY)
between '2016-01-01' and '2016-03-31'
and
DAYOFWEEK(DATE_ADD('2016-01-01', INTERVAL ROW DAY))=1;
I need some help querying my calendar/dates table
Scenario: I have a "calendar" table with dates and times (see below), users will set their available dates, usually day by day with available time slots for each day. So my table looks like this:
+------+------------+---------------------+---------------------+
| ID | user_id | start_date | end_date |
+------+------------+---------------------+---------------------+
| 1 | 1 | 2016-09-01 08:00:00 | 2016-09-01 16:00:00 |
| 2 | 1 | 2016-09-03 00:00:00 | 2016-09-03 23:59:59 |
| 3 | 1 | 2016-09-04 00:00:00 | 2016-09-04 16:00:00 |
| 4 | 1 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 |
| 5 | 2 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 |
| 6 | 2 | 2016-09-07 08:00:00 | 2016-09-07 16:00:00 |
| 7 | 2 | 2016-09-08 08:00:00 | 2016-09-08 16:00:00 |
| 8 | 2 | 2016-09-08 18:00:00 | 2016-09-08 22:00:00 |
+------+------------+---------------------+---------------------+
We have 2 users here so I want the following:
If I search for start_date = 2016-09-05 08:00:00 and end_date = 2016-09-05 16:00:00 it should return user 1 and 2. Since both of them has an entry with these dates. Same goes as well if start_date = 2016-09-05 09:00:00 and end_date = 2016-09-05 15:00:00, this should as well return both users since the time im searching for is between the time slots as shown in the example.
Second scenario is a little bit more tricky, If user search for start_date = 2016-09-03 08:00:00 and end_date = 2016-09-04 16:00:00 i want the query to check the following:
see if the user is available each day at these times.
so in this case, is the user available on 2016-09-03 between 08:00:00 and 16:00:00 and as well on 2016-09-04 between 08:00:00 and 16:00:00.
In the example over this should return user 1.
Im open for suggestion on re-designed my schema if needed.
Hope some can help me with this.
DEMO include some aditional code comment, and show how the query evolve . Also I add another row for user_id = 2 to show how only match one of the two days in the range.
SELECT U.`user_id`
FROM (
select a.selectDate,
CONCAT(a.selectDate, ' ', time(#s_date)) as start_time,
CONCAT(a.selectDate, ' ', time(#s_date)) as end_time
from (
select '1900-01-01' + INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) + (10000 * e.a)) DAY as selectDate
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as e
) a
CROSS JOIN (SELECT #s_date := '2016-09-03 08:00:00', #e_date := '2016-09-04 16:00:00') par
-- CROSS JOIN (SELECT #s_date := '2016-09-05 08:00:00', #e_date := '2016-09-05 16:00:00') par
-- CROSS JOIN (SELECT #s_date := '2016-09-05 09:00:00', #e_date := '2016-09-05 15:00:00') par
WHERE selectDate BETWEEN date(#s_date)
AND date(#e_date)
) D
CROSS JOIN (SELECT DISTINCT `user_id` FROM Table1) U
LEFT JOIN Table1 T
ON U.`user_id` = T.`user_id`
AND D.start_time <= T.`end_date`
AND D.end_time >= T.`start_date`
GROUP BY U.`user_id`
HAVING COUNT(U.`user_id`) = COUNT(T.`user_id`);
OUTPUT
Step 1: create a list of dates, in this case 273 years
Step 2: select all dates between the range define in the parameters, also include the time window to each date.
Step 3: join all together to see what dates have user in that time window
Step 4: select only user with a time window for all dates
I've got the following query:
SELECT GVA12.FECHA_EMIS, GVA12.COD_VENDED, sum(GVA12.IMPORTE)
FROM GVA12
WHERE Month(GVA12.FECHA_EMIS)=Month(curDate())
AND Year(GVA12.FECHA_EMIS)=Year(curDate())
AND GVA12.COD_VENDED="EX"
AND GVA12.T_COMP="FAC"
GROUP BY GVA12.FECHA_EMIS
This is for a monthly graph. I've got two questions. One, how can I show all the dates of the months as zero (the ones that don't have any sales), and two, is there any way to make the values go adding up, so the last value is the total of all the values.
Edit:
#Bluefeet with your query, I created the following,
SELECT Month(Days.DMY), Year(Days.DMY), GVA12.COD_VENDED, sum(GVA12.IMPORTE)
FROM Days
left join GVA12
on Month(Days.DMY) = Month(GVA12.FECHA_EMIS)
and Year(Days.DMY) = Year(GVA12.FECHA_EMIS)
WHERE Month(GVA12.FECHA_EMIS)=Month(curDate())
AND Year(GVA12.FECHA_EMIS)=Year(curDate())
AND GVA12.COD_VENDED="EX"
AND GVA12.T_COMP="FAC"
GROUP BY Month(Days.DMY), Year(Days.DMY) WITH ROLLUP
I got the result attached (screenshot).
It doesn't show all the days of the month as I wanted. What can I do?
Edit #3
It works now, but I want to add another filter. This filter is added here http://sqlfiddle.com/#!2/9d46c/1
To get the total you can use the GROUP BY WITH ROLLUP which should give you the Total of all dates:
SELECT GVA12.FECHA_EMIS, GVA12.COD_VENDED, sum(GVA12.IMPORTE)
FROM GVA12
WHERE Month(GVA12.FECHA_EMIS)=Month(curDate())
AND Year(GVA12.FECHA_EMIS)=Year(curDate())
AND GVA12.COD_VENDED="EX"
AND GVA12.T_COMP="FAC"
GROUP BY GVA12.FECHA_EMIS WITH ROLLUP
As far as returning dates that do not exist, There are many questions on SO that answer that including the following. Sometimes it is easier in MySQL to create a table to join on:
generate days from date range
Get a list of dates between two dates
Edit #1: if you have a table with dates, then you could use something similar to this:
SELECT Month(d.yourDateCol), Year(d.yourDateCol), g.COD_VENDED, sum(g.IMPORTE)
FROM dates d
left join GVA12 g
on Month(d.yourDateCol) = Month(GVA12.FECHA_EMIS)
and Year(d.yourDateCol) = Year(GVA12.FECHA_EMIS)
WHERE Month(g.FECHA_EMIS)=Month(curDate())
AND Year(g.FECHA_EMIS)=Year(curDate())
AND g.COD_VENDED="EX"
AND g.T_COMP="FAC"
GROUP BY Month(d.yourDateCol), Year(d.yourDateCol) WITH ROLLUP
Edit #2: Without seeing your full table structure or some sample data, here is a version of the query that is working:
select month(d.dmy) Month,
year(d.dmy) Year,
coalesce(sum(g.Importe), 0) TotalImporte
from dates d
left join GVA12 g
on month(d.dmy) = month(g.FECHA_EMIS)
and year(d.dmy) = year(g.FECHA_EMIS)
group by month(d.dmy), year(d.dmy) WITH ROLLUP
See SQL Fiddle with Demo. This returns the month/year for each month/year in the dates table even if it does not exist in the GVA12 table,
Edit #3: If you want the running total, not just the final total, then you should be able to use the following:
SET #running_total := 0;
SELECT month(Days.DMY) Month,
Year(Days.DMY) Year,
Date(Days.DMY) Date,
g.COD_VENDED,
#running_total := #running_total + Coalesce(TotalImport, 0) as TotalImport
FROM Days
left join
(
select FECHA_EMIS,
COD_VENDED,
sum(IMPORTE) TotalImport
from GVA12
group by Date(FECHA_EMIS), Year(FECHA_EMIS)
) g
on date(Days.DMY) = date(g.FECHA_EMIS)
and g.COD_VENDED='EX'
and Month(g.FECHA_EMIS)=Month(curDate())
and Year(g.FECHA_EMIS)=Year(curDate())
WHERE month(days.dmy)=Month(curDate())
See SQL Fiddle with Demo
The result is:
| MONTH | YEAR | DATE | COD_VENDED | TOTALIMPORT |
----------------------------------------------------------------------------
| 1 | 2013 | January, 01 2013 00:00:00+0000 | (null) | 0 |
| 1 | 2013 | January, 02 2013 00:00:00+0000 | EX | 1000 |
| 1 | 2013 | January, 03 2013 00:00:00+0000 | EX | 4000 |
| 1 | 2013 | January, 04 2013 00:00:00+0000 | (null) | 4000 |
| 1 | 2013 | January, 05 2013 00:00:00+0000 | (null) | 4000 |
| 1 | 2013 | January, 06 2013 00:00:00+0000 | (null) | 4000 |
| 1 | 2013 | January, 07 2013 00:00:00+0000 | (null) | 4000 |
a couple ideas:
one - you need some data values to compare against - so you could build a new table to hold all the dates - statically - then you do an outer join to that to make sure you get the zeroes.
two - i'm not sure about mysql - but in Oracle this is a LAG function. maybe that is a helpful pointer for further research.
Have a look at this link, there is explained how to list all dates between 2 dates
Get a list of dates between two dates
you can list using the following but I think there are better solution in the above link:
select a.Date
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a
where a.Date between '2012-12-01' and '2012-12-31';