Mysql find date range - mysql

Given the following values YYYY-MM-DD
$start = 2012-03-21
$stop = 2012-07-15
and the following records in the DB, also YYYY-MM-DD
DATE_FROM DATE_TO PRICE
2012-01-01 2012-03-01 123
2012-03-01 2012-04-08 123
2012-04-09 2012-06-04 456
2012-06-04 2012-07-02 789
2012-07-02 2012-07-16 111
2012-07-17 2012-08-17 222
How can I select all records that fall within the range of $start - $stop? This should include all except the last and first row
Attempt below, which gets records 2 - 4 but not 5.
SELECT date_from, date_to, price
FROM periods
WHERE (date(date_from) <= '$start' OR date(date_to) <= '$stop')

You want logic something like this:
date_to >= $start AND date_from <= $stop
If this is what you are looking for:
Start-----Stop
From-------------------To
Start-----Stop
From-------------------To
Start-----Stop
From-------------------To
Notice that Start always has to come before To AND Stop always has to come after From for this overlap to occur.
Let me know if any of my assumptions are off of what you are looking for. But, either way, I always find something like this easier to write down so you can visualize and easily see the greater than/less than situations.

SELECT date_from, date_to, price
FROM periods
WHERE (date_from BETWEEN '$start' AND '$stop') AND (date_to BETWEEN '$start' AND '$stop')

Related

MySQL get dates for drawing barchart

I'm trying to pull all information inside a given date range from my database using something like this query:
SELECT transactionDate, SUM(transactionTotal)
FROM transaction
WHERE transactionDate BETWEEN '2014-06-01' AND '2014-08-11'
AND transactionType = 'end'
GROUP BY DAYOFMONTH(transactionDate)
ORDER BY transactionDate ASC
But somehow I only get the data for 1 month
2014-06-01 20:38:05 4811500.00
2014-06-02 20:42:59 5924950.00
2014-06-03 20:44:38 3811500.00
2014-06-04 11:45:13 4472000.00
2014-06-05 15:34:53 7922000.00
2014-06-06 17:45:28 5027000.00
2014-06-07 11:25:38 4378000.00
2014-06-08 07:59:04 4250000.00
2014-06-09 08:41:49 4766500.00
2014-06-10 01:23:35 4071000.00
2014-06-11 01:01:30 1459000.00
2014-06-12 15:05:08 2960000.00
2014-06-13 00:47:09 1160000.00
2014-06-14 16:52:20 4208000.00
2014-06-16 00:05:18 3947500.00
2014-06-17 00:18:39 4926000.00
2014-06-18 00:33:38 4244500.00
2014-06-19 00:43:39 4045000.00
2014-06-20 22:47:54 2649500.00
2014-06-21 23:06:04 4030000.00
2014-06-22 23:19:22 945500.00
2014-06-23 23:29:27 3015000.00
2014-06-24 23:35:56 2420000.00
2014-06-25 00:02:03 3920000.00
2014-06-26 00:50:33 4841000.00
2014-06-27 10:39:14 4095000.00
2014-06-28 07:43:06 5605500.00
2014-06-29 11:48:24 1939000.00
2014-06-30 10:49:50 3620000.00
As you can see, I get the results from 2014-06-01 to 2014-06-01 even when all other dates also have data to display.
Hope you can help me, thanks!
You're misusing GROUP BY and the pernicious MySQL GROUP BY extension is biting you. You're grouping your data into 31 buckets with your GROUP BY DAYOFMONTH() , so there's no way you'll get more than 31 rows in your result set. You're then (misusing the extension) displaying some arbitrarily selected transaction_date value from each of your 31 groupings. It happens to be a June date, and this has tricked you into thinking you've only selected June records. You've actually selected all the dates in your range, but mistakenly grouped July and August records with your June records. Ouch.
Second, using BETWEEN to select date ranges from a DATETIME column isn't quite right, because it gets the end of the range wrong. BETWEEN '2014-06-01' AND '2014-08-11' gets the items dated from the first of June up until the very first moment of August 11th. So something happening at noon on August 11th won't get selected.
Here is the query you need to do this job correctly.
SELECT DATE(transactionDate),
SUM(transactionTotal)
FROM transaction
WHERE transactionDate >= '2014-06-01'
AND transactionDate < '2014-08-11' + INTERVAL 1 DAY
AND transactionType = 'end'
GROUP BY DATE(transactionDate)
ORDER BY DATE(transactionDate) ASC
What's going on here? First, we're grouping by just the date of each transaction, using DATE(), and we're including that grouped value in our result set with SELECT DATE().
Second, the date range selection takes everything on or after midnight on June first, up until the moment right before midnight on August 12th. That's the point of transactionDate < '2014-08-11' + INTERVAL 1 DAY. It takes the whole day's worth of items for August 11.
There's a writeup of this corner of SQL tech here: http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
Use the following sql query to get desired results
SELECT transactionDate, SUM(transactionTotal) FROM transaction WHERE transactionDate BETWEEN '2014-06-01' AND '2014-08-11' AND transactionType = 'end' GROUP BY CAST(transactionDate AS DATE) ORDER BY transactionDate ASC

Mysql Between in Between

how to select data between 2 dates in between 2 dates? for example :
start_date - end_date -- title
2014-01-28 2014-02-03 test
2014-02-01 2014-02-15 ests
2014-02-28 2014-03-03 sets
2014-03-01 2014-03-10 sste
the problem is, i want to select data between 2014-02-02 and
2014-02-28 with first three of them selected because the first three
data is included on 2nd month.
i tried this, but not works
SELECT title FROM my_tables WHERE start_date BETWEEN 2014-02-02 AND 2014-02-28
how it works?
Two periods overlap when one begins before the other ends, and the other ends after the first begins. Here is the correct logic:
SELECT title
FROM my_tables
WHERE start_date <= '2014-02-28' and
end_date >= '2014-02-02';
Note that date constants need to be in single quotes.
Here is a SQL Fiddle showing it working.
Add single quote to date constant
SELECT title FROM my_tables WHERE start_date BETWEEN '2014-02-02' AND '2014-02-28'
A date range overlaps with another when either the start or the end is within that other range:
given range: |----|
range 1 |----| overlaps with given range, because end_date is in that range
range 2 |----| overlaps with given range, because start_date is in that range
range 3 |----| does not overlap with given range, because both start and end date are not in that range
SELECT title FROM my_tables
WHERE (start_date BETWEEN '2014-02-02' AND '2014-02-28')
OR (end_date BETWEEN '2014-02-02' AND '2014-02-28');

MySQL: Group by Austral year?

Let's say we have a simple table like so
DATE VALUE
--------------------
2013-01-01 23
2013-06-12 34
2013-07-22 788
2013-12-16 234
2014-01-23 56
2014-04-19 88
2014-09-23 7987
2014-11-05 66
2015-02-17 987
2015-05-05 896
Now let's suppose we want to extract the mean values grouped by year, we would use
SELECT AVG(`VALUE`) FROM tablename GROUP BY YEAR(`DATE`)
However, what if we define the year not from January to December, but rather from July to June (which makes quite a bit of sense for a lot of data if you're living in the Southern hemisphere).
I am sure there must be an easy way to achieve a July YEAR to June YEAR+1 grouping. It just seems to elude me.
-- EDIT --
Awesome! Two good solutions arrived within minutes of posting this question, that both deserved to be accepted. I accepted Roland's solution because of its brevity, but Leo Tara's reply made me aware that I forgot about outputting the associated austral year. So based on both answers I came up with this solution which does exactly what I was asking for:
SELECT
YEAR(`DATE` - INTERVAL 6 MONTH) as `australyear`,
AVG(`VALUE`)
FROM tablename
GROUP BY YEAR(`DATE` - INTERVAL 6 MONTH)
Just add 6 month to the date when grouping. I don't know the exact syntax in case of mysql, sorry.
Pseudocode:
SELECT AVG(`VALUE`) FROM tablename GROUP BY YEAR(`DATE` + '6 MONTHS');
Try this:
SELECT AVG(`VALUE`)
FROM tablename
GROUP BY
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END
If you want to show year on field list you must rewrite your query in this way:
SELECT
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END, AVG(`VALUE`)
FROM tablename
GROUP BY
CASE
WHEN MONTH('DATE') BETWEEN 1 AND 6 THEN YEAR('DATE') - 1
ELSE YEAR(`DATE`)
END
Test on Sql Fiddle

MySQL date_add behaviour

I've written some SQL to give me a range of dates between two times like so:
select date_add(x.min_date, interval ((t500.id-1) * 30) minute) period
from (
select '2013-08-05T23:00' as min_date, '2013-08-06T01:00' as max_date
) x,
t500
where date_add(x.min_date, interval ((t500.id-1) * 30) minute) <= x.max_date);
Where T500 is a trivial table with column id of 1 to 500 I use for simulating a loop.
Now I expect this to return:
2013-08-05 23:00:00
2013-08-05 23:30:00
2013-08-06 00:00:00
2013-08-06 00:30:00
2013-08-06 01:00:00
and finish there. But instead it carries on until 2013-08-06 23:30:00. I tried different max dates and it always returns dates to the end of the day. Could someone explain what's happening and how to make it stop when I want?
First thing that comes to mind would be casting your date strings into a date format instead of a string for example:
cast('2013-08-05T23:00' as smalldatetime)

Mysql query for group by month

I am looking to do something like get all rows from table
where date >='2012-05-05' and date<='2012-07-20'
I want MySQL to return "group by" rows mont wise incremented from
2012-05-05 to 2012-06-05(incerement 1 month)
2012-06-06 to 2012-07-06(increment 1` month)
and remaining 2012-07-07 to 2012-07-20 (group the remaining 14 days)
how can i write my query to achieve the same?
Thank you...
Try this solution:
You can GROUP BY the number of months elapsed from your parameter minimum (2012-05-05) + 1 to the date in each row via the TIMESTAMPDIFF() function:
GROUP BY TIMESTAMPDIFF(MONTH, '2012-05-05' + INTERVAL 1 DAY, date)
The reason why we +1 day to your minimum parameter is because:
2012-05-05 to 2012-06-04 is 0 months, but...
2012-05-05 to 2012-06-05 is 1 month
^ Because of that, the row(s) on 2012-06-05 would be grouped separately from dates that had 0 months elapsed when we actually want it grouped WITH them.
Edit: I was fiddling around with this solution not only grouping by the month intervals, but also displaying the from and to dates of each interval.
Check it out:
SQLFiddle Demo
You could use the case expression and then group by on the result of case.
SELECT
CASE
WHEN where date >='2012-05-05' and date<='2012-06-05' THEN 1
WHEN where date >='2012-06-06' and date<='2012-07-06' THEN 2
ELSE 3
END AS period, COUNT(*)
FROM your_table
GROUP BY period
Hope this help, I assumed the date range is dynamic like this :
2012-01-01 to 2012-02-01
2012-02-02 to 2012-03-02
2012-03-03 to 2012-04-03
2012-04-04 to 2012-05-04
2012-05-05 to 2012-06-05
...
So, I can group it using :
SELECT *, IF(day(date)>=month(date), month(date), month(date)-1) as PERIOD
FROM your_tablename
GROUP BY PERIOD;