MySQL getting the closest row available based on date - mysql

I'm measuring different kind of events daily and get records looking like that:
id measurement_date value
111 2020-12-01 21:30:00 100
111 2020-12-02 22:00:12 110
111 2020-12-03 21:35:17 80
114 2020-12-02 21:47:56 780
114 2020-12-04 21:55:47 700
....
Then I am having a query transforming the data to get the difference between 2 measurements.
I am running this transform on different windows of time (1 day, 7 days, 1 month).
For 1 day it is quite straightforward as I either have a measurement or if missing I have no intermediary data to compensate and therefore place a 0.
Here is the query I use:
SELECT id,
(ft.value - ft2.value) as progression,
FROM feed_table ft
JOIN feed_table ft2 on ft2.id = ft.id
AND date_format(ft2.date, '%Y-%m-%d') = date_format(date_sub(CURDATE(), interval 1 day), '%Y-%m-%d')
WHERE date_format(ft.date, '%Y-%m-%d') = date_format(CURDATE(), '%Y-%m-%d')
However for longer windows, like 7 days, for example, I would like to make use of the intermediary data if they exist.
Let's say I am measuring on the 7 days window between today 2020-12-08 and 7 days before 2020-12-01, but I only have the following measurements which are neither today nor 7 days ago but are still inside the 7 days window:
id measurement_date value
111 2020-12-02 21:30:00 200
111 2020-12-06 21:30:00 300
Then the query above with a 7D interval and the right settings should return :
id progression
111 100
(max date value - min date value in the 7 days window)
I was thinking of aggregating by user_id and using the min-max date in the having close, but my self-join wouldn't work anymore...
Any idea?

Related

MySQL Looking for a pattern of temperatures

Looking for a pattern of temperatures
Trying to produce a list of results from a simple table that records temperature and time every 5 minutes. The table only has two columns 'temp' and 'ttime'. The time is recorded as MySQL timestamp.
What I need to do is check for any patterns where the temperature goes over 40 for more than two hours within a 24 hour period using just the data from same table and there are thousands of rows of data.
Quick sample of data:
temp
ttime
35
2022-08-14 12:05:00
40
2022-08-14 12:10:00
41
2022-08-14 12:15:00
37
2022-08-14 12:20:00
Not sure how to even start something like this.
I'd try something like
SELECT * FROM data d1
WHERE temp >= 40
AND temp >= ALL (
SELECT temp FROM d2
WHERE d2.ttime BETWEEN
date_add(d1.ttime, INTERVAL -2 HOUR)
AND d1.ttime
);
to get the first record after two hours higher than 40 degrees (can't verify at the moment)

Excel WEEKNUM() vs MySQL YEARWEEK()

I am creating a clock-in time system and so far I have been able to get user clock in time for today and user clock in time for the current week.
The final step is to get user current time for the current pay period.
I have created a list of pay period start & end dates in Excel.
Whenever you use a function like Excel WEEKNUM() or MySQL YEARWEEK(), these functions come with an additional option parameter.
The links below show the differences between these modes in a table.
Excel WEEKNUM() table reference
MySQL YEARWEEK() table reference
My question is, if we do payroll biweekly, which mode do I set in Excel WEEKNUM() that corresponds to MySQL YEARWEEK()?
Attached spreadsheet clock.logic.xlsx
Thank you for any help.
At first the good news: The Excel ISOWEEKNUM function corresponds to the MySQL WEEKOFYEAR which is WEEK(date,3). So determining ISO week numbers is possible.
But all other WEEK modes are simply crap because the definition of the first week in year does not fit any logic used elsewhere. For example, take the simplest mode having Sunday as the first day of the week and the first week of the year is the week, the first day of the year falls in. This is what Excels WEEKNUM function returns with Return_type 1 or omitted. This should be MySQLs WEEK in modus 0 (0-53) or 2 (1-53). But what the heck?
SELECT WEEK('2008-01-01',0); -> 0
SELECT WEEK('2008-01-01',2); -> 52
So MySQL tells us, Tuesday, 2008-01-01, is in week 52 of 2007?
Really? Why?
Because the rule "Week 1 is the first week … with a Sunday in this year" is not fulfilled by MySQL. Instead it seems for MySQL the first week starts with the first Sunday in this year.
So except of the ISO week numbers, all other week numbers from MySQL are wrong. One could think: Let us take modus 0 and simply add 1 to the result. But that fails in 2012. Because there 2012-01-01 is Sunday and there MySQL gives week number 1 in modus 0 as well as in modus 2.
Examples:
Excel:
Date WEEKNUM ISOWEEKNUM
2008-01-01 1 1
2008-02-01 5 5
2008-02-03 6 5
2008-02-04 6 6
2008-12-31 53 1
2009-01-01 1 1
2009-02-01 6 5
2009-12-31 53 53
2012-01-01 1 52
2012-02-01 5 5
2012-12-31 53 1
2016-01-01 1 53
2016-02-01 6 5
2016-12-31 53 52
MySQL:
drop table if exists tmp;
create table tmp (d date);
insert into tmp (d) values
('2008-01-01'),
('2008-02-01'),
('2008-02-03'),
('2008-02-04'),
('2008-12-31'),
('2009-01-01'),
('2009-02-01'),
('2009-12-31'),
('2012-01-01'),
('2012-02-01'),
('2012-12-31'),
('2016-01-01'),
('2016-02-01'),
('2016-12-31');
select d as 'Date', week(d,0), week(d,3) from tmp;
Result:
Date week(d,0) week(d,3)
2008-01-01 0 1
2008-02-01 4 5
2008-02-03 5 5
2008-02-04 5 6
2008-12-31 52 1
2009-01-01 0 1
2009-02-01 5 5
2009-12-31 52 53
2012-01-01 1 52
2012-02-01 5 5
2012-12-31 53 1
2016-01-01 0 53
2016-02-01 5 5
2016-12-31 52 52
If you want to calculate hours in current pay period in Excel, given a two week pay period, then I'd suggest that you don't need week numbers at all (in fact that overcomplicates the calculation, especially at the start or end of the year)
If you have dates in A2:A100 and hours worked on those dates in B2:B100, and a list of pay period start dates in Z2:Z10 then you can get hours in current pay period with this formula
=SUMIF(A2:A100,">="&LOOKUP(TODAY(),Z2:Z10),B2:B100)
I imagine your actual setup is more complicated, but some variation on the above can probably still be used

Find the rate for given date from mysql table

I have a table:
adate pdt_id pdt_rate
2017-10-02 5 20
2017-10-05 5 25
2017-10-07 5 23
2017-10-11 5 20
I have to find the rate of product with pdt_id 5 for between dates 2017-10-01 and 2017-10-10
For 2017-10-01 there is no rate in table so I take the lesser date like 2017-09-30 (no record), 2017-09-29 (no record) and so on (unfortunately no record). So I turn the bigger date than 2017-10-01 is 2017-10-02 (yes, there is a record) so I stop the searching and finalize as
2017-10-01 rate is 20
Now find the next date 2017-10-02, there is record and is 20
2017-10-02 rate is 20
Following the similar criteria I got
2017-10-03 rate is 20
2017-10-04 rate is 20
2017-10-05 rate is 25
....
2017-10-10 rate is 23
So my question is How to Find the rate for given date if the date exist other wise take the rate of lesser date and if the lesser date is not exist find the rate of next bigger date?
Finally we get rate for all dates(from start date to end date).
How can I achieve this?
$begin = new DateTime('2017-10-01');
$end = new DateTime('2017-10-10');
$daterange = new DatePeriod($begin, new DateInterval('P1D'), $end);
foreach($daterange as $date){
$dateval = $date->format("Y-m-d");
// here I want find the rate for each date
}
Here is one method:
select t.*
from t
order by (adate <= '2017-10-01') desc
abs(datediff(adate, '2017-10-01'))
limit 1;

Difference in day between date i have passed in query and field date of table

I have History Table of points Earned as below
ID Points earn_date
1 10 2017-04-04
2 8 2017-04-01
3 12 2017-04-28
4 7 2017-05-16
5 9 2017-06-03
Now From earn_date till today date i want to get the days difference using query
First I have Tried with following Query
SELECT *,earn_date - '2017-06-17' AS RemainDays FROM customer_earning
then i have tried with DATEDIFF Function but didn't get the result
How can i get the days result
Output i want is if i pass today date then
ID Points earn_date Days
1 10 2017-04-04 74
2 8 2017-04-01 78
3 12 2017-04-28 50
4 7 2017-05-16 32
This doesn't do what you want?
SELECT ce.*, DATEDIFF('2017-06-17', ce.earn_date) AS RemainDays
FROM customer_earning ce;
Given the information in the question, this should calculate the remaining days.
You could be explicit about the type casts, but I doubt that will make a difference:
SELECT ce.*,
DATEDIFF(DATE('2017-06-17'), DATE(ce.earn_date)) AS RemainDays
FROM customer_earning ce;
try this below query:
select *,DATEDIFF(day,Earn_Date,GETDATE()) as RemainDays FROM customer_earning
Use Below Query
SELECT *,DATEDIFF(datepart,startdate,enddate) AS RemainDays FROM customer_earning;
For Example :
SELECT *,DATEDIFF(day,GETDATE(),earn_date) AS RemainDays FROM customer_earning;
startdate: like Today Date [GETDATE()]
enddate: like earn_date
[datepart] is like what do you want to calculate. for example if you want to calculate days, date part is day, if you want to calculate months, date part is month

Get average day or week values

I have statistical data like this:
time val1
1424166578 51
1424166877 55
1424167178 57
1424167477 57
time is a unix timestamp. There is one record every 5 minutes excluding nights and sundays. This continues over several weeks.
Now I want to get these values for an average day and an average week. The result should include values for every 5 minutes like normal but for average past days or weeks.
The result should look like this:
time val1
0 43.423
300 46.635
600 51.887
...
So time could be a timestamp with relative time since day or week start. Perhaps it is better to use DATETIME... not sure.
If I use GROUP BY FROM_UNIXTIME(time, '%Y%m%d') for example I get one value for the whole day. But I want all average values for all days.
You seem to be interested in grouping dates by five minute intervals instead of dates. This is fairly straightforward:
SELECT
HOUR(FROM_UNIXTIME(time)) AS HH,
(MINUTE(FROM_UNIXTIME(time)) DIV 5) * 5 AS MM,
AVG(val1) AS VAL
FROM your_table
WHERE time > UNIX_TIMESTAMP(CURRENT_TIMESTAMP - INTERVAL 7 DAY)
GROUP BY HH, MM
The following result will explain how date is clamped:
time FROM_UNIXTIME(time) HH MM
1424166578 2015-02-17 14:49:38 14 45
1424166877 2015-02-17 14:54:37 14 50
1424167178 2015-02-17 14:59:38 14 55
1424167477 2015-02-17 15:04:37 15 00
I would approach this as:
select date(from_unixtime(time)) as day, avg(val)
from table t
group by date(from_unixtime(time))
order by day;
Although you can use the format argument, I think of that more for converting the value to a string than to a date/time.