Retrieve multiple rows using DATE BETWEEN in MySQL - mysql

I have the below table structure.
ID | FromDate | ToDate
1 | 2020-01-02 | 2020-06-01
2 | 2020-08-01 | 2020-12-01
3 | 2020-01-02 | 2020-11-28
4 | 2020-04-01 | 2020-05-28
When I pass 2 input parameters named fromDate and toDate, it should select the relevant records.
E.g. If FromDate = 2020-01-01 and ToDate = 2020-06-01, it should return records with IDs 1 and 4 since those two records are between the dates as the parameters supplied.
I am using the below method at the moment and I feel like it's wasting a lot of resources.
AND ToDate IN (select * from
(select adddate('2000-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) v
where selected_date between '2021-01-02 00:00:00' and '2022-03-02 00:00:00') ORDER BY name ASC,lt.ID ASC<code>
Is there any other way to achieve this task?

select * from table_name where fromDate>'2020-xx-xx' AND ToDate<'2020-xx-xx';
this query format can get records between insertion dates

Related

Query to print null if there are no data available for the selected date

Suppose I have data available for 09-02-2020 and I want last 8 days data between 01-02-2020 to 09-02-2020 but if there is no data available for 01-02-2020 to 08-02-2020 so then just print " - " at the place of data.
I want the query for this scenario.
Expected Output -:
|Date counts|
|09-02-2020 15 |
|08-02-2020 - |
|07-02-2020 - |
|06-02-2020 - |
|05-02-2020 - |
|04-02-2020 - |
|03-02-2020 - |
|02-02-2020 - |
|01-02-2020 - |
Assuming that data is stored in Test table with date and value. Try below query:
select t1.selected_date,case when t2.val is null then "-" else convert(t2.val,char) end as val from
(select selected_date from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) v
where selected_date between '2020-02-01' and '2020-02-09'
)
t1
left join test t2 on t1.selected_date=t2.date order by t1.selected_date desc;
Output:
2020-02-09 -
2020-02-08 -
2020-02-07 -
2020-02-06 -
2020-02-05 -
2020-02-04 1
2020-02-03 6
2020-02-02 5
2020-02-01 1
If the data type of date column is varchar then you can convert it using CONVERT(column_name as date) and above will use the date format as YYYY-MM-DD so you will have to change the date format using DATE_FORMAT.

Total Users Per Day

Problem
I want to show all users for a specific range lets say from 2020-01-01 to from 2020-01-05.
I have a table user where all users are saved. Imagine following table:
user
id | createdAt
1 2020-01-01
2 2020-01-02
3 2020-01-03
4 2020-01-03
5 2020-01-05
The outcome should be (relating to the above user table):
date | count
2020-01-01 1
2020-01-02 2
2020-01-03 4
2020-01-04 4
2020-01-05 5
What I have so far
I have a query that returns the example above as needed:
SELECT COALESCE((SELECT COUNT(*) FROM user u WHERE DATE(u.createdAt) <= DATE(dates.gen_date) AND u.role = 'USER' GROUP BY dates.gen_date ),0) AS y, dates.gen_date AS x FROM user u, (select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_date from
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4) v
where gen_date between DATE(?) and DATE(?)) AS dates GROUP BY x;
But the execution of this statement is really slow by huge number of users and a large time range.
I thought also of a materialized view but this would be only the last way out.
Database used: MySql 5.7
Test
SELECT (dates.mindate + INTERVAL (t0.n+10*t1.n+100*t2.n+1000*t3.n) DAY) `date`,
COUNT(users.id) `count`
FROM users,
(SELECT ? mindate, ? maxdate) dates,
(select 0 n 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) t0,
(select 0 n 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) t1,
(select 0 n 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) t2,
(select 0 n union select 1 union select 2) t3
WHERE users.createdAt <= (dates.mindate + INTERVAL (t0.n+10*t1.n+100*t2.n+1000*t3.n) DAY)
GROUP BY `date`
HAVING `date` <= dates.maxdate
ORDER BY `date`
It must be less expensive.

Get list of Dates based on conditions via SQL

Currently having a little difficulty with respect to getting a list of dates.
I currently have the following SQL:
SELECT DISTINCT DATE(startDate) activity_date
, CASE WHEN (DATE(endDate) - DATE(startDate)) > 0 THEN DATE(endDate) ELSE FALSE END multiEvent
FROM activities
WHERE startdate BETWEEN '2017-08-01' AND '2017-08-31'
AND accountid = 578
ORDER
BY DATE(startdate)
Which gives the following result:
activity_date | multiEvent
2017-08-07 | 0
2017-08-07 | 2017-08-10
2017-08-18 | 0
However, what i am trying to achieve is, if multiEvent is not zero, then list the dates between the dates of activity_date & multiEvent into a single column.
Result I am trying to achieve:
activity_date |
2017-08-07 |
2017-08-07 |
2017-08-08 |
2017-08-09 |
2017-08-10 |
2017-08-18 |
ideas? :)
You need to first find a way to create rows for dates between activity_date and multiEvent. This query will produce the intended resultset of dates, as individual rows.
select date(eachDate) as eachDate from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) as eachDate
from
(select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) as v
where
eachDate between date('2017-08-07')
and date('2017-08-10') order by eachDate asc ;
This will produce a result like
eachDate
2017-08-07
2017-08-08
2017-08-09
2017-08-10
Now, we need to fit in the above query with your existing query to get the intended output. The query would look something like this.
select
activity_date
from
(select
date(startDate) as activity_date
from
activities
where
startdate between date('2017-08-01') and date('2017-08-31')
and accountid = 578
and NOT (DATE(endDate) - DATE(startDate)) > 0
union all
select
eachDate
from
(select date(eachDate) as eachDate
from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) as eachDate
from
(select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) as v
where
eachDate between date('2017-08-01')
and date('2017-08-31')) as dates_table
join
(select
date(startDate) as startDate,
date(endDate) as endDate
from
activities
where
startdate between date('2017-08-01') and date('2017-08-31')
and accountid = 578
and (date(endDate) - date(startDate)) > 0 ) as activities_table
on dates_table.eachDate between activities_table.startDate and activities_table.endDate) as main
order by
main.activity_date asc;
and the output looks like this.
activity_date
2017-08-07
2017-08-07
2017-08-08
2017-08-09
2017-08-10
2017-08-18

How to display all the dates between multiple two dates in a table?

I want to display all the dates between two dates for a particular record
And this is the table :
ID Start_Date End_Date
1 2013-01-14 2013-01-18
2 2013-02-01 2013-02-04
and now i want to get all the dates between from date and to date.
Expected output
ID Date
1 2013-01-14
1 2013-01-15
1 2013-01-16
1 2013-01-17
1 2013-01-18
2 2013-02-01
2 2013-02-02
2 2013-02-03
2 2013-02-04
guide me to write query for that with out creating any extra tables.
I have already tried this following query
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4) v
where selected_date between '2012-02-10' and '2012-02-15'
its working fine for single record. but i want get all the date intervals from my table
Updated
i have 6 qty of chairs for all days. So one user book 3 chars on 2013-01-14 to 2013-01-18 another person book 2 chars on 2013-01-17 to 2013-01-20. So my expected output shown below.
ID Date Available
1 2013-01-14 3
1 2013-01-15 3
1 2013-01-16 3
1 2013-01-17 5
1 2013-01-18 5
1 2013-01-19 2
1 2013-01-20 2
1 2013-01-21 2
How about
select
t.id,
DATE_FORMAT(a.Date,'%Y-%m-%d') as 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
join test t on a.Date between t.Start_Date and t.End_Date
order by t.id,Date
DEMO
First, I don't know your specific use case, but this feels ripe for more optimization. However, how about this?
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
(select 0 t0 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) t0,
(select 0 t1 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) t1,
(select 0 t2 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) t2,
(select 0 t3 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) t3,
(select 0 t4 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) t4) v
where (selected_date between '2012-02-10' and '2012-02-15') OR
(selected_date between '2012-03-10' and '2012-03-15') OR
(selected_date between '2012-04-10' and '2012-04-15')

Generate list of dates and count online posts each day

I want to receive results like the sample output.
Listed each day beween two dates and the number of online posts from a company.
For example:
TABLE
id | online_From | online_To | comp_id
11 | 2014-04-02 | 2014-04-05 | 20
12 | 2014-04-11 | 2014-04-16 | 21
13 | 2014-04-03 | 2014-04-07 | 20
17 | 2014-04-29 | 2014-04-30 | 23
19 | 2014-04-04 | 2014-04-11 | 20
I want to receive:
SAMPLE OUTPUT
2014-04-01 | 0
2014-04-02 | 1
2014-04-03 | 2
2014-04-04 | 3
2014-04-05 | 3
2014-04-06 | 2
2014-04-07 | 2
2014-04-08 | 1
2014-04-09 | 1
2014-04-10 | 1
2014-04-11 | 1
2014-04-12 | 0
2014-04-13 | 0
…
2014-05-07 | 0
I used this mysql code to list the requested dates (and also split into y/m/d/w for generate charts):
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date from (select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY y,m,d ORDER BY y ASC, m ASC, d ASC
2014-04-01|2014 |1 |14 |4 |0
2014-04-02|2014 |2 |14 |4 |1
2014-04-03|2014 |3 |14 |4 |2
…
This comes from: How to get list of dates between two dates in mysql select query
I tried a lot of things but I never became the hoped result.
I want to loop trough the dates and check the number of posts that where online that day.
Hopefully somebody can help me!
Thanks
This should get you started if you want a SQL-only answer. Have called your table comp_table...
select d.selected_date,d.d,d.m,d.y,
count(ct.id)
from
(
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date from (select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY selected_date
) d
left outer join comp_table ct on d.selected_date between ct.online_From and ct.online_To
group by d.selected_date
order by 1 asc
;
You might be better off periodically populating an all_dates table to use in place of the inline view though. Would be more performant!
EDIT
If you want to maintain 'gimme all dates even if they have a 0 count' yet filter the results e.g. by the comp_id column then simply change the left outer join to include your filter by clause. For example:
select d.selected_date,d.d,d.m,d.y,
count(ct.id)
from
(
select selected_date, year(selected_date) as y, day(selected_date) as d, week(selected_date) as w, month(selected_date) as m from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
selected_date from (select 0 i 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) t0,
(select 0 i 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) t1,
(select 0 i 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) t2,
(select 0 i 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) t3,
(select 0 i 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) t4) v
where selected_date between '2014-04-01' and '2014-05-07'
GROUP BY selected_date
) d
left outer join comp_table ct
on d.selected_date between ct.online_From and ct.online_To
and ct.comp_id = 20
group by d.selected_date
order by 1 asc
;
If you have not already installed it, I recommend you install common_schema. Once that's installed you can use the numbers table to simplify your query.
For example this query should give you the desired output:
select days.day,count(distinct your_table.id) from
(
select '2014-04-01' + interval n day AS day
from common_schema.numbers
having day between '2014-04-01' and '2014-05-07'
) days
left outer join your_table on your_table.online_From <= days.day and your_table.online_To >= days.day
group by days.day
order by days.day