Obtaining max values for each day in the past 28 days - mysql

I've seen some of the past posts where there were questions about extracting max values for each day. Based on this, I tried SELECT ts, MAX(current) FROM mytable WHERE ts > date_add(now(), interval -28 day); but I only got one row back which is not what I want.
In this table, ts is my timestamp and current is another column of values. I want to get the max current values for each day in the past 28 days. However, my current values are recorded into the table every 30 mins each day. Therefore, there are many ts values for each day. Could this be the reason why the above query design doesnt work? If so, how can I amend it?
Here is an example of how my table look like for a few rows:
+---------------------+--------------+
| ts | current |
+---------------------+--------------+
| 2018-01-20 16:27:10 | 439.37 |
| 2018-01-20 17:00:18 | 378.07 |
| 2018-01-20 17:30:15 | 204.80 |
| 2018-01-20 18:00:16 | 196.50 |
| 2018-01-20 18:30:16 | 179.40 |
| 2018-01-20 19:00:16 | 183.00 |
| 2018-01-20 19:30:16 | 105.00 |

Related

How to select date today from each day that has in between date?

I have a problem about the data that I want to display. Basically I have this table.
history_table:
| history_date_from | history_date_to |
+-----------------+---------------+
| 2019-10-12 | 2019-10-12 |
| 2019-10-25 | 2019-10-28 |
| 2019-11-18 | 2019-11-22 |
| 2019-11-19 | 2019-11-25 |
| 2019-11-20 | 2019-11-20 |
The problem that I'm having is what if today is already 2019-11-19. I still want to show the third row until 2019-11-22.
Here is my current query:
SELECT history_date_from,history_date_to
FROM history_table
WHERE DATE(history_date_from)= CURDATE() BETWEEN DATE(history_date_from) AND DATE(history_date_to)
But the problem from my query is it will just depend on the CURDATE of the history_date_from, what I'm trying to achieve is to still get the third row for tomorrow until the end of the date depends on the history_date_to.
So if today 2019-11-19 the output should be:
| history_date_from | history_date_to |
| 2019-11-18 | 2019-11-22 |
| 2019-11-19 | 2019-11-25 |
because the history_date_to is still not done in terms of date.
Any help would be really appreciated, I think I'm just making thing complicated with my query.
You can use the following solution using BETWEEN:
SELECT *
FROM history_table
WHERE CURDATE() BETWEEN history_date_from AND history_date_to
demo on dbfiddle.uk
You don't need to check for the exact match on history_date_from. You want to know if the current date is in a specific period of time. So BETWEEN is a good way to go.

SQL - select x entries within a timespan

I'm creating a database (in MySQL) with a table of measurements. For each measurement I want to store the DateTime it came in. For showing plots within an app for different intervals (measurements of the day/week/month/year) I want sample the data points I have, so I can return e. g. 30 data points for the whole year as well as for the day/hour. This is the same as done with stock price graphs:
stock price plot for 1 day
vs
stock price plot for 1 month
As you can see, the amount of data points is the same in both pictures.
So how can I select x entries within a timespan in MySQL via SQL?
My data looks like this:
+====+====================+=============+==========+
| id | datetime | temperature | humidity |
+====+====================+=============+==========+
| 1 | 1-15-2016 00:30:00 | 20 | 40 |
+----+--------------------+-------------+----------+
| 2 | 1-15-2016 00:35:00 | 19 | 41 |
+----+--------------------+-------------+----------+
| 3 | 1-15-2016 00:40:00 | 20 | 40 |
+----+--------------------+-------------+----------+
| 4 | 1-15-2016 00:45:00 | 20 | 42 |
+----+--------------------+-------------+----------+
| 5 | 1-15-2016 00:50:00 | 21 | 42 |
+----+--------------------+-------------+----------+
| 6 | 1-15-2016 00:55:00 | 20 | 43 |
+----+--------------------+-------------+----------+
| 7 | 1-15-2016 01:00:00 | 21 | 43 |
+====+====================+=============+==========+
Let's say, I always want two data points (in reality a lot more). So for the last half hour I want the database to return data point 1 and 4, for the last ten minutes I want it to return 6 and 7.
Thanks for helping!
PS: I'm sorry for any errors in my English
OK, assuming a very simple systematic approach, you can get the first and last entry for any defined period:
select *
from table
where mydatetime =
(select
max(mydatetime)
from table
where mydatetime between '2017-03-01' and '2017-03-15'
)
OR mydatetime =
(select
min(mydatetime)
from table
where mydatetime between '2017-03-01' and '2017-03-15'
)
I believe your answer can be found at the following location:
https://stackoverflow.com/a/1891796/7176046
If you are looking to filter out any items not within your date/time your query would use:
Select * from table where Date/Time is (What you want to sort by)

Mysql timestampdiff sum between overlapped intervals

I have the following table structure:
+----+---------------------+---------------------+
| id | created_at | closed |
+----+---------------------+---------------------+
| 1 | 2017-04-03 04:00:00 | 2017-04-03 04:30:00 |
| 2 | 2017-04-03 04:25:00 | 2017-04-03 04:35:00 |
+----+---------------------+---------------------+
In my real SQL query I use timestampdiff to clacualte the diffirence between two dates in timestap field. There is no problem if the ctreated_at and closed_at of all records start in diffirent time intervals, so I would able to get time consumed for all rows as follows:
SELECT SUM(timestampdiff(SECOND, created_at, closed_at)) as TotalTime FROM table
My problem is like the shown table above, the time interval crossing. The above query will result 900 but it I should have 600
I have tried something like:
SELECT timestampdiff(
MINUTE,
a.created_at,
(SELECT max(b.closed) from times as b WHERE b.created_at < a.closed)
) as periods
FROM `times` as a
The result is:
+---------+
| periods |
+---------+
| 35 |
| 10 |
+---------+
Here I want only the first result whuch represnts the net time of the overlapped periods. Using MAX with the previous query should returns the first record but it will lead to neglect any other periods groups added in the futere supposed the table becomes:
+----+---------------------+---------------------+
| id | created_at | closed |
+----+---------------------+---------------------+
| 1 | 2017-04-03 04:00:00 | 2017-04-03 04:30:00 |
| 2 | 2017-04-03 04:25:00 | 2017-04-03 04:35:00 |
| 3 | 2017-04-03 05:00:00 | 2017-04-03 05:15:00 |
+----+---------------------+---------------------+
the above query returns:
+---------+
| periods |
+---------+
| 35 |
| 10 |
| 15 |
+---------+
Again here I don't want the second record because it describes its period which is previously counted in the first record. Indeed I don't know does it possible in MySQL to get (for the example above) only two records or even three records but the second is null, 0, negative value, etc to be distinguished among other really values.
You need to do group by the time on hourly basis and the take difference time for of max.
SELECT max(timestampdiff(
MINUTE,
a.created_at,closed) as periods
FROM `times` as a group by hour(created_at)
Now you will get result as per ur requirement.

How can I select all rows which have been inserted in the last day?

I have a table like this:
// reset_password_emails
+----+----------+--------------------+-------------+
| id | id_user | token | unix_time |
+----+----------+--------------------+-------------+
| 1 | 2353 | 0c274nhdc62b9dc... | 1339412843 |
| 2 | 2353 | 0934jkf34098joi... | 1339412864 |
| 3 | 5462 | 3408ujf34o9gfvr... | 1339412894 |
| 4 | 3422 | 2309jrgv0435gff... | 1339412899 |
| 5 | 3422 | 34oihfc3lpot4gv... | 1339412906 |
| 6 | 2353 | 3498hfjp34gv4r3... | 1339412906 |
| 16 | 2353 | asdf3rf3409kv39... | 1466272801 |
| 7 | 7785 | 123dcoj34f43kie... | 1339412951 |
| 9 | 5462 | 3fcewloui493e4r... | 1339413621 |
| 13 | 8007 | 56gvb45cf3454g3... | 1339424860 |
| 14 | 7785 | vg4er5y2f4f45v4... | 1339424822 |
+----+----------+--------------------+-------------+
Each row is an email. Now I'm trying to implement a limitation for sending-reset-password email. I mean an user can achieve 3 emails per day (not more).
So I need an query to check user's history for the number of emails:
SELECT count(1) FROM reset_password_emails WHERE token = :token AND {from not until last day}
How can I implement this:
. . . {from now until last day}
Actually I can do that like: NOW() <= (unix_time + 86400) .. But I guess there is a better approach by using interval. Can anybody tell me what's that?
Your expression will work, but has 3 problems:
the way you've coded it means the subtraction must be performed for every row (performance hit)
because you're not using the raw column value, you couldn't use an index on the time column (if one existed)
it isn't clear to read
Try this:
unix_time > unix_timestamp(subdate(now(), interval '1' day))
here the threshold datetime is calculated once per query, so all of the problems above have been addressed.
See SQLFiddle demo
You can convert your unix_time using from_unixtime function
select r.*
from reset_password_emails r
where now() <= from_unixtime(r.unix_time) - interval '1' day
Just add the extra filters you want.
See it here: http://sqlfiddle.com/#!9/4a7a9/3
It evaluates to no rows because your given data for unix_time field is all from 2011
Edited with a sqlfiddle that show the conversion:
http://sqlfiddle.com/#!9/4a7a9/4

Selecting max price from every 5 rows

I've been trying and trying and haven't been able to figure this out.
In stock charts that have Open, High, Low, Close, you can always chart every minute, 5 min, 10 min, hour, etc. I have data for every minute and I'm trying to select out the Open, High, Low, Close from that minute-by-minute data, but for every 5 minutes.
I have data similar to this:
__________________________________________________
| Date | TIME | TICKER | Open | High | Low | Close |
| 20121203 | 090000 | QQQQ | 23.54 | 24.12 | 23.01 | 23.24 |
| 20121203 | 090100 | QQQQ | 23.24 | 24.14 | 22.98 | 24.13 |
| 20121203 | 090200 | QQQQ | 24.13 | 25.88 | 23.75 | 25.81 |
| 20121203 | 090300 | QQQQ | 25.81 | 25.83 | 24.63 | 24.99 |
| 20121203 | 090400 | QQQQ | 24.99 | 25.21 | 23.89 | 24.12 |
| 20121203 | 090500 | QQQQ | 24.12 | 24.19 | 21.94 | 22.03 |
| 20121203 | 090600 | QQQQ | 22.03 | 22.97 | 20.68 | 21.44 |
| 20121203 | 090700 | QQQQ | 21.44 | 24.06 | 19.32 | 23.56 |
| 20121203 | 090800 | QQQQ | 23.56 | 25.48 | 23.07 | 25.01 |
| 20121203 | 090900 | QQQQ | 25.01 | 28.00 | 24.18 | 27.21 |
| 20121203 | 091000 | QQQQ | 27.21 | 27.55 | 24.31 | 24.31 |
I need to grab the max(high) for the rows that have a time >= 090000 (that's 9 a.m.) 09 hours 00 minutes 00 seconds.
Similar to this, I need min(low), and then I'll grab the close price when time is 090400 because I'm getting every 5 minutes. I could also use the open of the next 5 minute increment, so that's flexible.
I've used nested SELECT statements, multiple joins, etc. The problem is that the MySQL execution time is about 1 second per row returned. That's crazy slow when you figure there are 12 rows per hour (60 minutes / 5 minutes = 12), and then because I'm actually doing FOREX, the trading is around the clock, so 24 hours. That gives me 288 per day, or just under 5 minutes per day. To do 1 year of data (~ 250 trading days) would be about 20 hours. There has to be a faster way.
I've got some solutions for this with the ID being continuous, and though that might be easiest, I'm not 100% sure my data would be correct in doing that. The reason why is that on Fridays the trading day ends at normal business hours in NY and opens up with the first trading in Tokyo (about mid-afternoon in the United States).
I've looked at GROUP BY, but I'm not sure how I can group the data to get a group of 5 where the time is within 5 minutes of each 5 minute group.
Thanks for your thoughts and discussion.
Jarod
This should show max(high) and min(low) for every 5 minutes
SELECT Max(high),
Min(low)
FROM tbl
GROUP BY ROUND(Unix_timestamp(Date(Concat(`date`, `time`))) / ( 5 * 60 ))
In the Group by clause we concat your date time column. So it forms something like 20121203090000. This is one the format that is recognized as date in mysql. So we pass it to date() function. Then its converted to UNIX_TIMESTAMP. Its divided by 5 mins timespan. The result will be a float value. But we require same value for a specific time span. Hence the ROUND(). It makes the floating value to the nearest integer. To understand how its working run this query.
SELECT high,
low
Unix_timestamp(Date(Concat(`date`, `time`))) / ( 5 * 60 ) `5-min span`
ROUND(Unix_timestamp(Date(Concat(`date`, `time`))) / ( 5 * 60 )) `5-min span rounded`
FROM tbl
try this:
SELECT CONCAT(DATE,SUBSTRING(Time,1,2),"["
,IF(SUBSTRING(Time,4,1)<5,CONCAT(SUBSTRING(Time,3,1),"0"),CONCAT(SUBSTRING(Time,3,1),"5"))
,"-"
,IF(SUBSTRING(Time,4,1)<5,CONCAT(SUBSTRING(Time,3,1),"5"),CONCAT(SUBSTRING(Time,3,1)+1,"0"))
,"]") AS timeStr ,MAX(High) ,MIN(LOW) FROM tb1 GROUP BY timeStr;
http://sqlfiddle.com/#!2/6b748/1