Find date scope from MySQL efficiently - mysql

Here is my DiscountPeriod table's structure:
id
room_id
date_from
date_last
discount
Imagine that we have discount starting 01 December 2017 and ending in in 10 December 2017.
I'm searching for date-range to see if it has discount.
So date range might be totally or partly inside some of discount periods. 3 example date-ranges for search:
From 02 December to 10 December (fully inside one of discount periods)
From 20 November to 4 December (partly inside)
From 5 December to 15 December (partly inside)
Expected for all of 3 examples above is to get discount that starts in 01 December 2017 and ends in 10 December 2017.
Currently my query takes only those results which is completely inside exact period from database.
It looks like this:
SELECT * FROM `DiscountPeriod` WHERE (`room_id`=1517) AND (`date_last` >= '2017-12-12') AND (`date_from` <= '2017-12-20');
Question is, how to fit all of 3 possible search cases into 1 query for efficient searching in MySQL database tables?
Expected result is
All of following scopes: From 02 Dec to 10 Dec, From 20 Nov to 4 Dec, From 5 Dec to 15 Dec should return back 1-10 december discount.

This looks like an overlapping range problem. If you want to return all discounts which overlap with 1-10 December 2017, then try the following query:
SELECT *
FROM DiscountPeriod
WHERE
room_id = 1517 AND
'2017-12-01' <= date_last AND '2017-12-10' >= date_from;
Here is a demo which uses your test data. All three discount ranges you suggested show up in the result set. But a range lying completely outside 1-10 December 2017 is absent, as we would expect.
Demo

Related

How can I filter rows according to a date range when only year, month and day are available?

I have data such as these:
id year month day
1 2020 11 1
2 2020 11 1
3 2020 12 31
4 2020 12 31
5 2021 1 1
6 2021 1 1
7 2021 1 31
8 2021 1 31
9 2021 2 1
10 2021 2 12
I wish to SELECT all rows between 2 dates.
I realise that I could convert the year/month/day to a timestamp which would make this very easy. Actually the timestamp is already there, however, the underlying table is huge (tens of billions of rows) and the DB administrator has set up indexing/clustering on the year/month/day columns in order provide performant queries. Queries that directly use the actual timestamp in a WHERE clause take far too long to run (hours) whereas queries that use year/month/day run within seconds.
Here is a db<>fiddle
Just to clarify, this is a way to do it, but your problem is your DBA, your arquitechture, etc. etc. You won't solve this by this way, neither the time or resources wasted. Maybe you need to ask a proper way to do this with non SQL database in DBA stack exchange site.
Anyway, for the to-know way:
Convert data to datestamp ISO: yyyyMMdd with CONCAT and LPAD
Compare the data as normal integer
Example: (of course you can change the values of your search)
SELECT * from dt WHERE CONCAT(year,LPAD(month, 2, '0'),LPAD(day, 2, '0')) BETWEEN 20201231 AND 20210101

Selecting between dates in mysql

Need to track and bill delivers based on date, for example if a deliver came in After 01/18/2010 but before 02/11/2010 it would be billed to Job no. 198.
I pretty much know it would be:
SELECT `no` FROM `jobs` WHERE 'start_date' >'2010-01-18' AND <`2010-02-11`;
in order to get '2010-01-18' AND < '2010-02-11', I have to look in the data base of course that defeats the purpose
I am given the Var=$delivery_date
And I am stuck right here.
How can I get the between dates without looking each time.
Sample of data base
no Start Date
198 2010 01 18 14:35
199 2010 02 11 12:10
200 2010 03 07 12:33
201 2010 03 31 17:35
202 2010 05 25 05:05
203 2010 06 20 01:05
204 2010 07 14 08:50
205 2010 07 21 11:31
206 2010 09 07 03:47
I hope I explained it well enough. I look at the manual and other questions but it always seems like they only have one date that is a variable and all of mine are
PS changing the format or method of the tables is not an option unless you can point me towards the time travel section
You can use the following select statement:
SELECT * FROM jobs WHERE date(start_date) BETWEEN "2010-02-08" AND "2010-03-15";
so you only take the date portion into account, not the time.
so with your date format it would be something like
SELECT * FROM jobs WHERE date(STR_TO_DATE(start_date, '%Y %m %d %h:%i')) BETWEEN "2010-02-08" AND "2010-03-15"
Looks like you want to find a jobs record with the largest start_date that's also less than $delivery_date. Here's the query
SELECT no
FROM jobs
WHERE `start_date` < $delivery_date
ORDER BY `start_date` DESC LIMIT 1
If $delivery_date is set to 2010-02-08, the above query will return 198 like you expected.
If $delivery_date is set to 2010-03-15, the above query will return 200.
thanks to ekad this worked perfectly
SELECT no
FROM jobs
WHERE start_date < $delivery_date
ORDER BY start_date DESC LIMIT 1
after the query the job no i need is first one

MySQL query results with weekday between 2 dates

I need a query to get results from a table that has 2 columns
Column startdt (datetime), Column enddt (datetime)
there are some records with startdt 2013-07-19 and enddt 2013-07-29
I need to get the records with weekday = 1 (Tuesday)
the record with date 2013-07-19 is weekday 4 and ends 2013-07-29 which is 0
Actually i want to get the results that has for weekday Monday or another weekday.
You can check the above link for an example
http://sqlfiddle.com/#!2/a80ce/1
If you don't understand what i want to do let me explain. I have an event that starts July 15 and ends July 25. (Starts Monday and ends Thursday) The user selects one of the week days (Monday, Tuesday etc). If he select Tuesday then i want the query that will get all events that are active in Tuesday.
I already found the answer so if anyone want to check it
SELECT articleid,startdt,enddt,dayofweek(startdt), DATEDIFF(enddt,startdt) datedf
FROM events
WHERE (dayofweek(events.startdt) <= 3 AND dayofweek(events.enddt) >= 3)
OR DATEDIFF(enddt,startdt) >=6
(3 is the number of the weekday "Tuesday")
How about using the comments that other people gave you and use a query that combines both dayofweek and a simple greater/smaller/equal syntax as follows:
SELECT * FROM events where dayofweek(events.startdt) <= 6 AND dayofweek(events.enddt) >= 6
This gives the following results if the user specified a friday (= 6):
ARTICLEID STARTDT ENDDT
4 July, 12 2013 00:00:00+0000 July, 26 2013 00:00:00+0000
6 July, 16 2013 00:00:00+0000 July, 20 2013 00:00:00+0000
I do think that you are better of using dayofmonth however as this (maybe just to me) makes it clearer, possibly combining the use of both to ensure that it's active on a friday.
The OP indicates that events which are in the history should also be retrieved and as such the following query does what he wants:
SELECT * FROM events where dayofweek(events.startdt) <= 6 AND dayofweek(events.enddt) >= 6 OR DATEDIFF(enddt,startdt) >=6
How about this solution:
first you convert the day of week in format that 6 is Saturday and 7 is sunday(it's easier for me)
if(dayofweek(o.start_date) = 1, 7, dayofweek(o.start_date) -1)
after that you calc the days from the start_date needed to reach some of the weekdays
(7 - if(dayofweek(o.start_date) = 1, 7, dayofweek(o.start_date) -1)
finally you make sure that the difference in days between the two dates is no less that the above calculation
(7 - if(dayofweek(o.start_date) = 1, 7, dayofweek(o.start_date) -1) <= datediff(o.end_date, o.start_date)

MySql Query- Date Range within a Date Range

I use mySql 5 and IIS.
I have products, that have a start date field and an end date field.
I need to run a query that will take user entered Start and End dates, and output the number of days that the product ran within the date range.
Example:
Offer1 - July 1 2011 thru July 31 2011
Query - July 1 2011 thru Sept 15 2011
Results = 31
Example:
Offer1 - July 1 2011 thru July 31 2011
Query - July 1 2011 thru July 15 2011
Results = 15
If your products have a start_date and an end_date and your query has a qstart_date and a qend_date, then we want the number of days between:
GREATEST(start_date, qstart_date)
and
LEAST(end_date,qend_date)
. In MySQL I think this looks like
1 + DATEDIFF ( 'd' , GREATEST(start_date, qstart_date) , LEAST(end_date,qend_date) )
And you'll want to ignore negative numbers, replacing them with "0".

Get name of day from month, year, and day

Does anyone know a way to convert a month, year, and day into the day's name for any year? Example:
function convert(day, year, month)
...
return "Monday"
end
Thanks in advance!
You can use the following method:
This method uses codes for different
months and years to speed up the
calculation of the day of the week.
You might even be able to memorize the
codes. We'll use December 16, 2482 as
an example.
Take the last 2 digits of the year. In
our example, this is 82.
Divide by 4, and drop any remainder.
82 / 4 = 20, remainder 2, so we think
"20."
Add the day of the month. In our
example, 20 + 16 = 36.
Add the month's key value, from the
following table. Jan Feb Mar Apr May
June July Aug Sept Oct Nov Dec 1 4 4
0 2 5 0 3 6 1 4 6
The month for our example is December,
with a key value of 6. 36 + 6 = 42.
If your date is in January or February
of a leap year, subtract 1. We're
using December, so we don't have to
worry about this step.
Add the century code from the
following table. (These codes are for
the Gregorian calendar. The rule's
slightly simpler for Julian dates.)
1700s 1800s 1900s 2000s 4 2 0 6
Our example year is 2482, and the
2400s aren't in the table. Luckily,
the Gregorian calendar repeats every
four hundred years. All we have to do
is add or subtract 400 until we have a
date that is in the table. 2482 - 400
= 2082, so we look at the table for the 2000s, and get the code 6. Now we
add this to our running total: 42 + 6
= 48.
Add the last two digits of the year.
48 + 82 = 130.
Divide by 7 and take the remainder.
This time, 1 means Sunday, 2 means
Monday, and so on. A remainder of 0
means Saturday.
How to calculate the day of the week
A quickl google for "day of week from date algorithm" showed up this Wikipedia article
But depending on the dates you need to work with, beware the strange history of Gregorian calendar adoption