Last value of last hour - mysql

I want to extract la values from the last recording of the previous hour.
The Table have: DateHour (TIMESTAMP) and Energy (FLOAT)
Id________DateHour_____________Energy
..........................................................................
18350____2019-10-05 18:57:44____231.38
18351____2019-10-05 18:59:45____231.33
..........................................................................
..........................................................................
18400____2019-10-05 19:51:00_____123.35
The time now is 19:51:15 let say.
I want to select the value with ID 18351 in the example above. I want to work even when the day changes.
Tied:
select *
from table1
where DateHour> (unix_timestamp()*1000 - 60*60*1000);
Not good.

Assuming you are using MySQL (which the code looks like):
select t1.*
from table1 t1
where datehour >= cast(date_format(now() - interval 1 hour, '%Y-%m-%d %h:00') as datetime) and
datehour < cast(date_format(now(), '%Y-%m-%d %H:00') as datetime)
order by datehour desc
limit 1;
MySQL doesn't have a convenient function (like date_trunc() in Postgres) that rounds a date/time value down to a particular unit. In this case, it uses string conversion for this purpose.
Note that the structure of the query makes it possible to use an index on datehour. That is important if an index is available and your table is large.

Related

SQL Query to get distinct values from a table and the difference between ordered rows

I have a real time data table with time stamps for different data points
Time_stamp, UID, Parameter1, Parameter2, ....
I have 400 UIDs so each time_stamp is repeated 400 times
I want to write a query that uses this table to check if the real time data flow to the SQL database is working as expected - new timestamp every 5 minute should be available
For this what I usually do is query the DISTINCT values of time_stamp in the table and order descending - do a visual inspection and copy to excel to calculate the difference in minutes between subsequent distinct time_stamp
Any difference over 5 min means I have a problem. I am trying to figure out how I can do something similar in SQL, maybe get a table that looks like this. Tried to use LEAD and DISTINCT together but could not write the code myself, im just getting started on SQL
Time_stamp, LEAD over last timestamp
Thank you for your help
You can use lag analytical function as follows:
select t.* from
(select t.*
lag(Time_stamp) over (order by Time_stamp) as lg_ts
from your_Table t)
where timestampdiff('minute',lg_ts,Time_stamp) > 5
Or you can also use the not exists as follows:
select t.*
from your_table t
where not exists
(select 1 from your_table tt
where timestampdiff('minute',tt.Time_stamp,t.Time_stamp) <= 5)
and t.Time_stamp <> (select min(tt.Time_stamp) from your_table tt)
lead() or lag() is the right approach (depending on whether you want to see the row at the start or end of the gap).
For the time comparison, I recommend direct comparisons:
select t.*
from (select t.*
lead(Time_stamp) over (partition by uid order by Time_stamp) as next_time_stamp
from t
) t
where next_timestamp > time_stamp + interval 5 minute;
Note: exactly 5 minutes seems unlikely. You might want a fudge factor such as:
where next_timestamp > time_stamp + interval 5*60 + 10 second;
timestampdiff() counts the number of "boundaries" between two values. So, the difference in minutes between 00:00:59 and 00:01:02 is 1. And the difference between 00:00:00 and 00:00:59 is 0.
So, a difference of "5 minutes" could really be 4 minutes and 1 second or could be 5 minutes and 59 seconds.

Why does including a timezone into a MySQL DATETIME query with a VIEW make the fractional seconds not equivalent?

I have a MySQL 8 DB with a DATETIME(4) field, and I've run into a weird case around equivalency in a VIEW. I've worked around it but I'm not sure why it is happening and I'd like to understand why.
I have a table with a field: date_time DATETIME(4). I have a VIEW where I turn this back into an ISO8601 string using DATE_FORMAT(date_time, '%Y-%m-%dT%T.%fZ') as date_time.
If I insert a row with a date like 2017-04-22T20:47:05.33523Z, and then the following query fails to find the row and I'm not sure why.
select * from EXAMPLE_VIEW where date_time >= '2017-04-22T20:47:05.335Z';
The following do work:
select * from EXAMPLE where date_time >= '2017-04-22T20:47:05.335Z';
select * from EXAMPLE where date_time >= '2017-04-22T20:47:05.335';
select * from EXAMPLE where date_time >= '2017-04-22T20:47:05.3350Z';
select * from EXAMPLE_VIEW where date_time >= '2017-04-22T20:47:05.335';
select * from EXAMPLE_VIEW where date_time >= '2017-04-22T20:47:05.3350Z'
Minimal example here: https://www.db-fiddle.com/f/ak7LTLzH7UJGgmPWS85dRE/1
Your problem is that when you perform the comparison in the VIEW you are comparing as strings, not dates. When you format the datetime with %f you get 6 digits of microseconds i.e. 2017-04-22T20:47:05.335200Z. Since you are comparing this as a string, the >= comparison with '2017-04-22T20:47:05.335Z' fails because 2 is less than Z.
The reason this test works in query 1 is that '2017-04-22T20:47:05.335Z' gets converted to a date (resulting in 2017-04-22T20:47:05.335000Z) before comparison, and that is less than 2017-04-22T20:47:05.335200Z.

Query data between the same date

Is it possible to do something like this?
select * from table where Date BETWEEN '2019-05-29' AND '2019-05-29'
Yes it is possible. If you have time part you could use DATE function to skip it:
SELECT * FROM table WHERE DATE(Date) BETWEEN '2019-05-29' AND '2019-05-29'
-- it may degrade performance, condition is not SARGable
Yes, but the better approach is:
select t.*
from table t
where t.Date >= date('2019-05-29') AND
t.Date < date('2019-05-29') + interval 1 day
Why is this better? It doesn't have a function on the column name, so it can make use of an index on the date column.
Yes you can, if you want to run it in a test window without manually changing the date within the code you can set it as a variable. Use trunc to get rid of time i.e there will be no 29-05-2019 23:59:00. If you want the same date within a time period remove the trunc and then you can set hours-minutes-seconds which makes your query more precise
SELECT t.*
FROM table t
WHERE t.date BETWEEN trunc(to_date(:datefrom, 'dd.mm.yyyy hh24:mi:ss')) AND
trunc(to_date(:dateto, 'dd.mm.yyyy hh24:mi:ss'))

How to SELECT all rows within a certain date/time range with a certain timestamp step size in MySQL?

I have a table that contains sensor data with a column timestamp that holds the unix timestamp of the time the sensor measurement has been taken.
Now I would like to SELECT all measurements within a certain date/time range with a specific time step.
I figured the first part out myself like you can see in my posted code snippet below.
// With $date_start and $date_stop in the format: '2010-10-01 12:00:00'
$result = mysqli_query($connection, "SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND timestamp < UNIX_TIMESTAMP($date_stop)
ORDER BY timestamp");
Now is there a convenient way in MySQL to include a time step size into the same SELECT query?
My table contains thousands of measurements over months with one measurement taken every 5 seconds.
Now let's say I would like to SELECT measurements in between 2010-10-01 12:00:00 and 2010-10-02 12:00:00 but in this date/time range only SELECT one measurement every 10 minutes? (as my table contains measurements taken every 5 seconds).
Any smart ideas how to solve this in a single query?
(also other ideas are very welcome :))
Since you take one measurement every 5 seconds, the difference between $date_start and the first matching measurement cannot be greater than 4. We then take one entry every 600 seconds (allowing for some discrepancy from clock to clock...)
SELECT sensor_1
FROM sensor_table
WHERE timestamp >= UNIX_TIMESTAMP($date_start)
AND
timestamp < UNIX_TIMESTAMP($date_stop)
AND
((timestamp - UNIX_TIMESTAMP($date_start)) % 600) BETWEEN 0 AND 4
ORDER BY timestamp;
It is not elegant, but you can do:
SELECT s.sensor_1
FROM sensor_table s
WHERE s.timestamp >= UNIX_TIMESTAMP($date_start) AND
s.timestamp < UNIX_TIMESTAMP($date_stop) AND
s.timestamp = (SELECT MIN(s2.timestamp)
FROM sensor_table s2
WHERE s2.timestamp >= 60 * 10 * FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)) AND
s2.timestamp < s2.timestamp >= 60 * 10 * (1 + FLOOR(UNIX_TIMESTAMP(s.timestamp) / (60 * 10)))
)
ORDER BY timestamp;
This selects the first in each 10 minute period.
I think that you could use a simple cursor in plSQL
CREATE TABLE StoreValuesId
(
valueId int primary key;
)
CREATE OR REPLACE procedure_store[date_start date,date_stop date]
DECLARE date_startUpdated date , date_stopUpdated date , date_diff TIME(7) = '00:10:00'
IS
BEGIN
SELECT date_start INTO date_startUpdated;
SELECT date_stop INTO date_stopUpdated;
IF timestamp BETWEEN date_start and date_stop then
INSERT INTO StoreValuesId values(timestamp)
date_startUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_startUpdated);
date_stopUpdated=DATEADD(SECOND, DATEDIFF(SECOND, 0, date_diff), date_stopUpdated);
END IF
COMMIT;
END
Then again the syntax might be wrong but I hope you'll get the idea (haven't played with sql in a while)

MySQL: Filter group view vs. inline select

i am just curious about performance of a summarize query on a mysql (5.5) database.
i have a table: timestamp | category | value.
now i try to
round timestamp to 5min of an hour
filter by timestamp for a day (very selective)
group with rounded timestamp and category and make the average of value
is it cheaper for the database server to 1) build the sql dynamically or 2) to make a view which does the group by and filter afterwards for the day?
my working solution is now 1) but i like the idea 2) from maintenance point of view more.
Or maybe someone can point me out a free, fast solution to compare the cost of both possibilities.
many thanks in advance & best regards,
martin
The most efficient way will be to filter down to one day and then do the work.
This is something like this:
select date_format(timestamp, '%Y-%m-%d %H'), floor(minute(timestamp) / 12),
category, avg(value)
from t
where timestamp >= '2015-01-01' and timestamp < '2015-01-02'
group by date_format(timestamp, '%Y-%m-%d %H'), floor(minute(timestamp) / 12)
order by min(timestamp);
Note the where clause. It is using an inequality, so you can use an index on t(timestamp).