splitting a time period into calendar months -- mysql - mysql

I am basically facing the same problem as described in this thread: http://www.experts-exchange.com/Database/Oracle/10.x/Q_24693813.html. The difference is that I need to find a solution with MYSQL.
I am dealing with an Electricity Usage table:
ID Account FromDate ToDate ElecUse ElecDemand ElecBillAmt
2903 100009 2010-10-14 2010-11-12 352400 668.1 12592.53
2904 100009 2010-11-12 2010-12-15 426400 666 14284.39
2905 100009 2010-12-15 2010-01-14 406800 708.4 13812.54
2906 100009 2010-01-14 2010-02-15 443200 697.9 14514.99
I would like to report the usage on a monthly basis beginning with the start of each month and ending with the end of each month. Thus, I would like to have a MYSQL query that can produce the following table from the above:
Account FromDate ToDate ElecUse ElecDemand ElecBillAmt
100009 2010-10-14 2010-10-31 206579 391.51 7381.74
100009 2010-11-01 2010-11-30 378402 639.24 13002.12
100009 2010-12-01 2010-12-31 410778 680.46 13859.46
100009 2011-01-01 2011-01-31 425290 701.14 14156.77
100009 2011-02-01 2011-02-15 207750 327 6803.85
I appreciate the help,
Dan

Turning columns into rows is often the job of a self-join or a union.
In all of your examples, your FromDate is the month before the ToDate. How about one query to get the number of days in the first month, and another to get the leftover days in the second month? Allocating ElecUse between the two would be easy after that.
Based on your actual data, you might need more queries (the two dates are in the same month, etc).
select fromdate, last_day(fromdate) as todate,
datediff(last_day(fromdate), fromdate) as days_in_month,
datediff(todate, fromdate) as days_in_range,
datediff(last_day(fromdate), fromdate)/datediff(todate, fromdate) as pct_in_month,
elecuse * (datediff(last_day(fromdate), fromdate)/datediff(todate, fromdate)) as elecuse_in_month
...
I left in the intermediate columns so you could see what was going on:
+------------+------------+---------------+---------------+--------------+------------------+
| fromdate | todate | days_in_month | days_in_range | pct_in_month | elecuse_in_month |
+------------+------------+---------------+---------------+--------------+------------------+
| 2010-10-14 | 2010-10-31 | 17 | 29 | 0.5862 | 206579.3102 |
+------------+------------+---------------+---------------+--------------+------------------+
UNION that with another query that does the second month in the original row's range, and you should be all set.
Heed #OllieJones' warnings about ElecDemand, though.

Related

Count days of daterange in daterange

I want to count how many days of a start and end-date are inside another start and end-date. Basically: How many days of the date 01.06.2020 - 06.06.2020 are inside the date 03.06.2020 - 31.12.2020. In this case the answer would be 4. The 3rd, 4th, 5th and 6th of June 2020.
I know that I can use TIMESTAMPDIFF to do calculations between 2 dates, but I can't wrap my head around a simple solution to do it with 2 dates inside 2 dates.
I can't believe nobody ever asked that question, but I can't find any solution to this.
Simple table:
+-------------+--------------+
| Start_date | End_date |
+-------------+--------------+
| 2020-06-03 | 2020-12-31 |
| 2014-09-08 | 2015-09-07 |
| 2015-01-15 | 2015-02-01 |
+-------------+--------------+
I look for something along the lines of:
SELECT * FROM available_dates WHERE TIMESTAMPDIFF(DAY,'2020-06-01','2020-06-06', Start_date, End_date) > 5
You can do this by taking the intersection of the two ranges using GREATEST on the start dates and LEAST on the end dates. Intersecting ranges will return a positive number, non-intersecting a negative one. So we use GREATEST again to zero out negative values to get the overlap. For example:
CREATE TABLE test (
`Start_date` DATE,
`End_date` DATE
);
INSERT INTO test
(`Start_date`, `End_date`)
VALUES
('2020-06-03', '2020-12-31'),
('2014-09-08', '2015-09-07'),
('2015-01-15', '2015-02-01');
SET #start = '2015-01-20';
SET #end = '2015=02-04';
SELECT GREATEST(TIMESTAMPDIFF(DAY, GREATEST(Start_Date, #start), LEAST(End_Date, #end))+1, 0) AS overlap
FROM test;
Output:
overlap
0
16
13
Demo on dbfiddle

MySQL query that will find all the entries with a datetime within the last hour of a month

I am trying to get all records in a MySQL database where a datetime column's value is within the final hour of any month (i.e. January 31st 23:00-23:59, February 28th 23:00-23:59) etc.
Is there a way to write a query without writing a bunch of "BETWEEN" statements?
Suppose I have the following table:
id | createtime
-------------------------
1 | 2018-01-30 23:37:11
2 | 2018-01-31 22:00:00
3 | 2018-01-31 23:37:11
4 | 2018-02-28 22:00:00
5 | 2018-02-28 23:33:00
I want a query that would select rows 3 and 5 (the last hour of January and February respectively).
Although it is not really performant for loads of data, there is an option to use different date/time functions to accomplish this:
You can test it with this simple line:
SET #mytime = "2018-09-30 22:59:59";
SELECT
#mytime,
LAST_DAY(#mytime),
HOUR(#mytime),
DAY(#mytime),
DAY(LAST_DAY(#mytime)),
IF(DAY(LAST_DAY(#mytime)) = DAY(#mytime) AND HOUR(#mytime) = 23, 1, 0) AS is_final_hour
;
Just play with the datetime variable that is set at the beginning to see different results.
After that you can use it in a query like so:
SELECT
t.mydatetime,
IF(DAY(LAST_DAY(t.mydatetime)) = DAY(t.mydatetime) AND HOUR(t.mydatetime) = 23, 1, 0) AS is_final_hour
FROM
mytable AS t
HAVING
is_final_hour = 1
;

mysql, getting time period between two time's when date and time are in separated column

I need to query the info in MySql where I'm given two time strings, so I need to find anything in between.
the format the table looks like
id | date | hour | other | columns | that are not important
-----------------------------------------------------------
1 | 2016-04-11| 1 | asdsa......
2 | 2016-04-11| 2 | asdasdsadsadas...
.
.
.
n | 2016-04-12| 23 | sadasdsadsadasd
Say I have the time strings 2016-04-11 1 and 2016-04-12 23 and I need to find all info from 1 to n. I can separate the date and hour and do a query using BETWEEN...AND for the date, but I have no idea how to fit the time into the formula. Using another BETWEEN definitely won't work, so I definitely need to fit the statement somewhere else. I'm not sure how to proceed though.
WHERE ((`date` = fromDate AND `hour` > fromHour) OR `date` > fromDate)
AND ((`date` = toDate AND `hour` < toHour) OR `date` < toDate)

Store multiple ranges in mysql table to make queries faster/easier

I have a data with multiple time ranges, for e.g. consider following columns
| from1 | to1 | from2 | to2 | from3 | to3 |
| 06:00 | 07:30 | 09:30 | 12:30 | 13:30 | 15:45 |
| 05:00 | 06:30 | 08:15 | 14:40 | 16:30 | 18:25 |
Now if I want to search for a time say 08:30, I would have to add 3 clauses in the query to match if the input occurs in range any out of all three from-to pairs.
In above case, it would return second row as 08:30 lies in the second from-to pair.
I want to know what would be the best practice to do this? It is ok even if I have to change my data model and not store those ranges in columns like I shown above. so that I can quickly and easily search through thousands of records
I can't think of a better alternative to this, please suggest.
I found this when i was searching for this problem.
It seems like your data model is not normalized. You should consider morjas suggestion about creating an additional table.
Below is a really ugly query that checks whether a date is in any of the three ranges, and then returns the matching rate.
select case
when date '2010-12-05' between range1_from and range1_to then range1_rate
when date '2010-12-05' between range2_from and range2_to then range2_rate
when date '2010-12-05' between range3_from and range3_to then range3_rate
end as rate
from events
where date '2010-12-05' between range1_from and range1_to
or date '2010-12-05' between range2_from and range2_to
or date '2010-12-05' between range3_from and range3_to;
ref.SQL query for finding a value in multiple ranges
Store your times as DATETIME and use BETWEEN
So:
where myDate BETWEEN '2011-03-18 08:30' AND '2011-09-18 09:00'

get the SUM between two given dates

if i want to get the total_consumption over a range of dates, how would i do that?
I thought i could do:
SELECT id, SUM(consumption)
FROM consumption_info
WHERE date_time BETWEEN 2013-09-15 AND 2013-09-16
GROUP BY id;
however this returns: Empty set, 2 warnings(0.00 sec)
---------------------------------------
id | consumption | date_time |
=======================================|
1 | 5 | 2013-09-15 21:35:03 |
2 | 5 | 2013-09-15 24:35:03 |
3 | 7 | 2013-09-16 11:25:23 |
4 | 3 | 2013-09-16 20:15:23 |
----------------------------------------
any ideas what i'm doing wrong here?
thanks in advance
You're missing quotes around the date strings: the WHERE clause should actually be written as...
BETWEEN '2013-09-15' AND '2013-09-16'
The irony is that 2013-09-15 is a valid SQL expression - it means 2013 minus 09 minus 15. Obviously, there's no date lying in between the corresponding results; hence an empty set in return
Yet there might be another, more subtle error here: you probably should have used this clause...
BETWEEN '2013-09-15 00:00:00' AND '2013-09-16 23:59:59'
... instead. Without setting the time explicitly it'll be set to '00:00:00' on both dates (as DATETIME values are compared here).
While it's obviously ok for the starting date, it's not so for the ending one - unless, of course, exclusion of all the records for any time of that day but midnight is actually the desired outcome.
SELECT SUM(consumption)
FROM consumption_info
WHERE date_time >= 2013-09-15 AND date_time <= 2013-09-16;
or
SELECT SUM(consumption)
FROM consumption_info
WHERE date_time BETWEEN 2013-09-15 AND 2013-09-16;
Its better to use CAST when comparing the date function.
SELECT id, SUM(consumption)
FROM consumption_info
WHERE date_time
BETWEEN CAST('2013-09-15' AS DATETIME)
AND CAST('2013-09-16' AS DATETIME)
GROUP BY id;