Mysql: Select all data between two dates - mysql

I have a mysql table with data connected to dates. Each row has data and a date, like this:
2009-06-25 75
2009-07-01 100
2009-07-02 120
I have a mysql query that select all data between two dates. This is the query:
SELECT data FROM tbl WHERE date BETWEEN date1 AND date2
My problem is that I also need to get the rows between date1 and date2 even if there is no data for a day.
So my query would miss the dates that are empty between 2009-06-25 and 2009-07-01.
Can I in some way add these dates with just 0 as data?

You can use a concept that is frequently referred to as 'calendar tables'. Here is a good guide on how to create calendar tables in MySql:
-- create some infrastructure
CREATE TABLE ints (i INTEGER);
INSERT INTO ints VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
-- only works for 100 days, add more ints joins for more
SELECT cal.date, tbl.data
FROM (
SELECT '2009-06-25' + INTERVAL a.i * 10 + b.i DAY as date
FROM ints a JOIN ints b
ORDER BY a.i * 10 + b.i
) cal LEFT JOIN tbl ON cal.date = tbl.date
WHERE cal.date BETWEEN '2009-06-25' AND '2009-07-01';
You might want to create table cal instead of the subselect.

Select * from emp where joindate between date1 and date2;
But this query not show proper data.
Eg
1-jan-2013 to 12-jan-2013.
But it's show data
1-jan-2013 to 11-jan-2013.

its very easy to handle this situation
You can use BETWEEN CLAUSE in combination with date_sub( now( ) , INTERVAL 30 DAY )
AND NOW( )
SELECT
sc_cust_design.design_id as id,
sc_cust_design.main_image,
FROM
sc_cust_design
WHERE
sc_cust_design.publish = 1
AND **`datein`BETWEEN date_sub( now( ) , INTERVAL 30 DAY ) AND NOW( )**
Happy Coding :)

Do you have a table that has all dates? If not, you might want to consider implementing a calendar table and left joining your data onto the calendar table.

IF YOU CAN AVOID IT.. DON'T DO IT
Databases aren't really designed for this, you are effectively trying to create data (albeit a list of dates) within a query.
For anyone who has an application layer above the DB query the simplest solution is to fill in the blank data there.
You'll more than likely be looping through the query results anyway and can implement something like this:
loop_date = start_date
while (loop_date <= end_date){
if(loop_date in db_data) {
output db_data for loop_date
}
else {
output default_data for loop_date
}
loop_date = loop_date + 1 day
}
The benefits of this are reduced data transmission; simpler, easier to debug queries; and no worry of over-flowing the calendar table.

you must add 1 day to the end date, using: DATE_ADD('$end_date', INTERVAL 1 DAY)

You can use as an alternate solution:
SELECT * FROM TABLE_NAME WHERE `date` >= '1-jan-2013'
OR `date` <= '12-jan-2013'

Related

Fetch values between two dates - MariaDB version: 10.1.37

I'm trying to fetch values between two dates, specifically 24hrs
SELECT *
FROM `transactions`
WHERE accnum = '1534610376'
AND tdate BETWEEN 20190311 AND 20190312
This query works fine but, i don't want it for a constant date, i have checked and seen many format but none seems to work. please help
If you "want records from today alone" - a simple way would be:
WHERE accnum = '1534610376'
AND DATE(tdate) = CURRENT_DATE()
However - To utilize an index, a column should not be wrapped into a function. So an efficient way would be
WHERE accnum = '1534610376'
AND tdate >= CURRENT_DATE()
AND tdate < CURRENT_DATE() + INTERVAL 1 DAY
A good index for this query would be INDEX(accnum, tdate).
I suggest you to put your date between quots like this:
SELECT *
FROM `transactions`
WHERE accnum = '1534610376'
AND tdate BETWEEN '20190311' AND '20190312'
After, you can define a user defined function like this :
CREATE FUNCTION BetweenDate(#toCompare VARCHAR(30), #rightDate DATE, #leftDate DATE)
RETURNS TABLE
AS
BEGIN
RETURN (
SELECT *
FROM transactions
WHERE accum = #toCompare AND tdate BETWEEN #rightDATE AND #leftDate
)
END;

Perform date and time calculation within subquery in insert statement

Anyone able to suggest how I could insert the current date + rental period in one query? The syntax in the code block doesn't work but DATE_ADD(NOW(),INTERVAL 1 DAY) works. I am trying to get the integer in INTERVAL to be based on the rental_period. I can do this with multiple queries but I am trying to do one (if possible).
INSERT INTO rental_details (rental_due_date, vg_id, rental_id) SELECT DATE_ADD(
NOW(), INTERVAL rental_period DAY), vg_id, 1 FROM status INNER JOIN video_games as vg ON
vg.status_id = status.status_id WHERE vg_id = 3;
Thanks.
This works but I need current date + rental_period (rental_period is an integer representing the days to add to current date):
INSERT INTO rental_details (rental_due_date, vg_id, rental_id) select rental_period,
vg_id, 1 from status inner join video_games as vg on vg.status_id = status.status_id
where vg_id = 3;
Your syntax appears to be correct. So, it is probably something about the data-type of your columns. You have not provided the details, but the following works:
create table vg_status
( rental_period integer);
create table rental_details
(due_date date);
insert into vg_status values (3);
insert into vg_status values (300);
insert into rental_details
select date_add(now(), interval rental_period day)
from vg_status
select *
from rental_details
You can see the output in SQL Fiddle

Nested MySQL Query w/ concat and adddate

I am trying to nest a few queries but so far am getting back error 1242: Subquery returns more than 1 row. I want more than one row, as I am working on a number of records.
I have 2 tables. One has a commencement date stored in 3 columns; yr_comm, mth_comm, day_comm. The 2nd table has a period of service (in years) for a number of users which is expressed as an integer (2.71, 3.45, etc).
I need to take this start date (from table 1), and add on the period of service (from table 2) to obtain an end date, but I only need to display the year.
I have 2 queries which work just fine when seperate, they result in the required values, however I am having trouble combining the queries to get the desired end result.
Query 1: Concatenate the 3 commencement values into date format
SELECT concat_ws('-', yr_comm, mth_comm, day_comm) AS date_comm
FROM table 1
Query 2: Convert the integer yrs_service into days
SELECT format(yrs_served * 365, 0) AS days_served
FROM table 2
Query 3: Use date_add function to add the days service to the commencement date
SELECT date_add(date_comm, INTERVAL days_served DAY) AS date_left
Can anyone suggest how I can achieve the above? Many thanks in advance.
EDIT - Here is the full query I am working on:
SELECT prime_minister.pm_name, yr_comm, party, ADDDATE(
(SELECT CONCAT_WS('-', yr_comm, mth_comm, day_comm) FROM ministry), INTERVAL
(SELECT FORMAT(yrs_served * 365, 0) FROM prime_minister) YEAR) AS date_left
FROM ministry JOIN prime_minister USING (pm_name)
WHERE party NOT LIKE '%labor%'
AND prime_minister.pm_name = ministry.pm_name
ORDER BY pm_name;
you can use user variables
SET #date = CONCAT_WS('-', 2012,1,1); -- paste your query here
SET #toAdd = (SELECT MONTH(CURDATE())); -- paste your query here
SELECT DATE_ADD(#date, INTERVAL #toAdd DAY) AS date_left
SQLFiddle Demo
which is the same as
SET #date = CONCAT_WS('-', 2012,1,1); -- paste your query here
SET #toAdd = (SELECT MONTH(CURDATE())); -- paste your query here
SELECT #date + INTERVAL #toAdd DAY AS date_left
SQLFiddle Demo
or without using variable, which is more longer,
SELECT (CONCAT_WS('-', 2012,1,1)) + INTERVAL (SELECT MONTH(CURDATE())) DAY AS date_left
SQLFiddle Demo

MySQL: Find Missing Dates Between a Date Range

I need some help with a mysql query. I've got db table that has data from Jan 1, 2011 thru April 30, 2011. There should be a record for each date. I need to find out whether any date is missing from the table.
So for example, let's say that Feb 2, 2011 has no data. How do I find that date?
I've got the dates stored in a column called reportdatetime. The dates are stored in the format: 2011-05-10 0:00:00, which is May 5, 2011 12:00:00 am.
Any suggestions?
This is a second answer, I'll post it separately.
SELECT DATE(r1.reportdate) + INTERVAL 1 DAY AS missing_date
FROM Reports r1
LEFT OUTER JOIN Reports r2 ON DATE(r1.reportdate) = DATE(r2.reportdate) - INTERVAL 1 DAY
WHERE r1.reportdate BETWEEN '2011-01-01' AND '2011-04-30' AND r2.reportdate IS NULL;
This is a self-join that reports a date such that no row exists with the date following.
This will find the first day in a gap, but if there are runs of multiple days missing it won't report all the dates in the gap.
CREATE TABLE Days (day DATE PRIMARY KEY);
Fill Days with all the days you're looking for.
mysql> INSERT INTO Days VALUES ('2011-01-01');
mysql> SET #offset := 1;
mysql> INSERT INTO Days SELECT day + INTERVAL #offset DAY FROM Days; SET #offset := #offset * 2;
Then up-arrow and repeat the INSERT as many times as needed. It doubles the number of rows each time, so you can get four month's worth of rows in seven INSERTs.
Do an exclusion join to find the dates for which there is no match in your reports table:
SELECT d.day FROM Days d
LEFT OUTER JOIN Reports r ON d.day = DATE(r.reportdatetime)
WHERE d.day BETWEEN '2011-01-01' AND '2011-04-30'
AND r.reportdatetime IS NULL;`
It could be done with a more complicated single query, but I'll show a pseudo code with temp table just for illustration:
Get all dates for which we have records:
CREATE TEMP TABLE AllUsedDates
SELECT DISTINCT reportdatetime
INTO AllUsedDates;
now add May 1st so we track 04-30
INSERT INTO AllUsedData ('2011-05-01')
If there's no "next day", we found a gap:
SELECT A.NEXT_DAY
FROM
(SELECT reportdatetime AS TODAY, DATEADD(reportdatetime, 1) AS NEXT_DAY FROM AllUsed Dates) AS A
WHERE
(A.NEXT_DATE NOT IN (SELECT reportdatetime FROM AllUsedDates)
AND
A.TODAY <> '2011-05-01') --exclude the last day
If you mean reportdatetime has the entry of "Feb 2, 2011" but other fields associated to that date are not present like below table snap
reportdate col1 col2
5/10/2011 abc xyz
2/2/2011
1/1/2011 bnv oda
then this query works fine
select reportdate from dtdiff where reportdate not in (select df1.reportdate from dtdiff df1, dtdiff df2 where df1.col1 = df2.col1)
Try this
SELECT DATE(t1.datefield) + INTERVAL 1 DAY AS missing_date FROM table t1 LEFT OUTER JOIN table t2 ON DATE(t1.datefield) = DATE(t2.datefield) - INTERVAL 1 DAY WHERE DATE(t1.datefield) BETWEEN '2020-01-01' AND '2020-01-31' AND DATE(t2.datefield) IS NULL;
If you want to get missing dates in a datetime field use this.
SELECT CAST(t1.datetime_field as DATE) + INTERVAL 1 DAY AS missing_date FROM table t1 LEFT OUTER JOIN table t2 ON CAST(t1.datetime_field as DATE) = CAST(t2.datetime_field as DATE) - INTERVAL 1 DAY WHERE CAST(t1.datetime_field as DATE) BETWEEN '2020-01-01' AND '2020-07-31' AND CAST(t2.datetime_field as DATE) IS NULL;
The solutions above seem to work, but they seem EXTREMELY slow (taking possibly hours, I waited for 30 min only) at least in my database.
This clause takes less than a second in same database (of course you need to repeat it manually dozen times and possibly change function names to find the actual dates). pvm = my datetime, WEATHER = my table.
mysql> select year(pvm) as _year,count(distinct(date(pvm))) as _days from WEATHER where year(pvm)>=2000 and month(pvm)=1 group by _year order by _year asc;
--ako

SQL query that returns all dates not used in a table

So lets say I have some records that look like:
2011-01-01 Cat
2011-01-02 Dog
2011-01-04 Horse
2011-01-06 Lion
How can I construct a query that will return 2011-01-03 and 2011-01-05, ie the unused dates. I postdate blogs into the future and I want a query that will show me the days I don't have anything posted yet. It would look from the current date to 2 weeks into the future.
Update:
I am not too excited about building a permanent table of dates. After thinking about it though it seems like the solution might be to make a small stored procedure that creates a temp table. Something like:
CREATE PROCEDURE MISSING_DATES()
BEGIN
CREATE TABLE TEMPORARY DATES (FUTURE DATETIME NULL)
INSERT INTO DATES (FUTURE) VALUES (CURDATE())
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 1 DAY))
...
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 14 DAY))
SELECT FUTURE FROM DATES WHERE FUTURE NOT IN (SELECT POSTDATE FROM POSTS)
DROP TABLE TEMPORARY DATES
END
I guess it just isn't possible to select the absence of data.
You're right — SQL does not make it easy to identify missing data. The usual technique is to join your sequence (with gaps) against a complete sequence, and select those elements in the latter sequence without a corresponding partner in your data.
So, #BenHoffstein's suggestion to maintain a permanent date table is a good one.
Short of that, you can dynamically create that date range with an integers table. Assuming the integers table has a column i with numbers at least 0 – 13, and that your table has its date column named datestamp:
SELECT candidate_date AS missing
FROM (SELECT CURRENT_DATE + INTERVAL i DAY AS candidate_date
FROM integers
WHERE i < 14) AS next_two_weeks
LEFT JOIN my_table ON candidate_date = datestamp
WHERE datestamp is NULL;
One solution would be to create a separate table with one column to hold all dates from now until eternity (or whenever you expect to stop blogging). For example:
CREATE TABLE Dates (dt DATE);
INSERT INTO Dates VALUES ('2011-01-01');
INSERT INTO Dates VALUES ('2011-01-02');
...etc...
INSERT INTO Dates VALUES ('2099-12-31');
Once this reference table is set up, you can simply outer join to determine the unused dates like so:
SELECT d.dt
FROM Dates d LEFT JOIN Blogs b ON d.dt = b.dt
WHERE b.dt IS NULL
If you want to limit the search to two weeks in the future, you could add this to the WHERE clause:
AND d.dt BETWEEN NOW() AND ADDDATE(NOW(), INTERVAL 14 DAY)
The way to extract rows from the mysql database is via SELECT. Thus you cannot select rows that do not exist.
What I would do is fill my blog table with all possible dates (for a year, then repeat the process)
create table blog (
thedate date not null,
thetext text null,
primary key (thedate));
doing a loop to create all dates entries for 2011 (using a program, eg $mydate is the date you want to insert)
insert IGNORE into blog (thedate,thetext) values ($mydate, null);
(the IGNORE keyword to not create an error (thedate is a primary key) if thedate exists already).
Then you insert the values normally
insert into blog (thedate,thetext) values ($mydate, "newtext")
on duplicate key update thetext="newtext";
Finally to select empty entries, you just have to
select thedate from blog where thetext is null;
You probably not going to like this:
select '2011-01-03', count(*) from TABLE where postdate='2011-01-03'
having count(*)=0 union
select '2011-01-04', count(*) from TABLE where postdate='2011-01-04'
having count(*)=0 union
select '2011-01-05', count(*) from TABLE where postdate='2011-01-05'
having count(*)=0 union
... repeat for 2 weeks
OR
create a table with all days in 2011, then do a left join, like
select a.days_2011
from all_days_2011
left join TABLE on a.days_2011=TABLE.postdate
where a.days_2011 between date(now()) and date(date_add(now(), interval 2 week))
and TABLE.postdate is null;