Using mysql, calculate the UNIX time difference between to rows - mysql

In this table, there are 100 different receipt_ids. Each receipt_id has multiple statuses. I want to calculate the time difference between the status_code DWRESULT_INIT and DWRESULT_SAVED. I want to group the results by receipt_id so I can see the time difference for all 100 receipt_ids in the DB. I am new to mysql, and am not sure how to accomplish this.

Use mysql's timestampdiff() function to calculate the difference and use from_unixtime() function to convert the timestamp into a datetime data type. To get the 2 status codes into a single record, use a subquery to get the init records only and join it back to your table filtered saved:
select t1.receipt_id, timestampdiff(second, from_unixtime(t2.event_time), from_unixtime(t1.event_time)) as diff
from yourtable t1
inner join
(select receipt_id, event_time
from yourtable
where status_code='DWRESULT_INIT') t2 on t1.receipt_id=t2.receipt_id
where t1.status_code='DWRESULT_SAVED'

SELECT
T1.type,
if(TIMESTAMPDIFF(MINUTE, FROM_UNIXTIME(T1.start_time),FROM_UNIXTIME(T1.end_time)) IS NULL,0,TIMESTAMPDIFF(MINUTE, FROM_UNIXTIME(T1.start_time),FROM_UNIXTIME(T1.end_time))) AS totalTimeInMinute,
T1.start_time AS startTime,
T1.end_time AS endTime
FROM (SELECT type,createdAt AS start_time,(SELECT createdAt FROM Worktime WHERE date='2020-10-08' AND createdAt > start_time LIMIT 1) AS end_time FROM Worktime
WHERE date='2020-10-08') AS T1

Related

SQL query Compare two WHERE clauses using same table

I am looking to compare two sets of data that are stored in the same table. I am sorry if this is a duplicate SO post, I have read some other posts but have not been able to implement it to solve my problem.
I am running a query to show all Athletes and times for the most recent date (2017-05-20):
SELECT `eventID`,
`location`,<BR>
`date`,
`barcode`,
`runner`,
`Gender`,
`time` FROM `TableName` WHERE `date`='2017-05-20'
I would like to compare the time achieved on the 20th May with the previous time for each athlete.
SELECT `time` FROM `TableName` WHERE `date`='2017-05-13'
How can I structure my query showing all of the ATHLETES, TIME on 13th, TIME on 20th
I have tried some methods such as UNION ALL for example
You can get the previous time using a correlated subquery:
SELECT t.*,
(SELECT t2.time
FROM TableName t2
WHERE t2.runner = t.runner AND t2.eventId = t.eventId AND
t2.date < t.date
ORDER BY t2.date DESC
LIMIT 1
) prev_time
FROM `TableName` t
WHERE t.date = '2017-05-20';
For performance, you want an index on (runner, eventid, date, time).

MySQL Date difference between two rows

I have a TABLE with Columns: USER_ID,TIMESTAMP and ACTION
Every row tells me which user did what action at a certain time-stamp.
Example:
Alice starts the application at 2014-06-12 16:37:46
Alice stops the application at 2014-06-12 17:48:55
I want a list of users with the time difference between the first row in which they start the application and the last row in which they close it.
Here is how I'm trying to do it:
SELECT USER_ID,DATEDIFF(
(SELECT timestamp FROM MOBILE_LOG WHERE ACTION="START_APP" AND USER_ID="Alice" order by TIMESTAMP LIMIT 1),
(SELECT timestamp FROM MOBILE_LOG WHERE ACTION ="CLOSE_APP" AND USER_ID="Alice" order by TIMESTAMP LIMIT 1)
) AS Duration FROM MOBILE_LOG AS t WHERE USER_ID="Alice";
I ask for the DATEDIFF between two SELECT queries, but I just get a list of Alice`s with -2 as Duration.
Am i on the right track?
I think you should group this table by USER_ID and find minimum date of "START_APP" and maximum of "CLOSE_APP" for each user. Also you should use in DATEDIFF the CLOSE_APP time first and then START_APP time in this case you will get positive value result
SELECT USER_ID,
DATEDIFF(MAX(CASE WHEN ACTION="CLOSE_APP" THEN timestamp END),
MIN(CASE WHEN ACTION="START_APP" THEN timestamp END)
) AS Duration
FROM MOBILE_LOG AS t
GROUP BY USER_ID
SQLFiddle demo
SELECT user_id, start_time, close_time, DATEDIFF(close_time, start_time) duration
FROM
(SELECT MIN(timestamp) start_time, user_id FROM MOBILE_LOG WHERE action="START_APP" GROUP BY user_id) start_action
JOIN
(SELECT MAX(timestamp) close_time, user_id FROM MOBILE_LOG WHERE ACTION ="CLOSE_APP" GROUP BY user_id) close_action
USING (user_id)
WHERE USER_ID="Alice";
You make two "tables" with the earliest time for start for each user, and the latest time for close for each user. Then join them so that the actions of the same user are together.
Now that you have everything setup you can easily subtract between them.
You have the int value because you use the function DATEDIFF, it shows you the number of days between two dates, if you want to have the number of hours and minutes and seconds between dates you have to use TIMEDIFF
Try this:
select t1.USER_ID, TIMEDIFF(t2.timestamp, t1.timestamp)
from MOBILE_LOG t1, MOBILE_LOG t2
where (t1.action,t1.timestamp) in (select action, max(timestamp) from MOBILE_LOG t where t.ACTION = "START_APP" group by USER_ID)
and (t1.action,t1.timestamp) in (select action, max(timestamp), max(id) from MOBILE_LOG t where t.ACTION = "CLOSE_APP" group by USER_ID)
and t1.USER_ID = t2.USER_ID
It will show you difference between two latest dates (startdate,enddate) for all user.
P.S: Sorry, I wrote it without any databases, and may be there are some mistakes. If you have problems with (t1.action,t1.timestamp) in (select...) split it on two: where t1.action in (select ...) and t1.timestamp in (select ...)

MySql -- Determine periods of missing data with query

I have a database that's set up like this:
(Schema Name)
Historical
-CID int UQ AI NN
-ID Int PK
-Location Varchar(255)
-Status Varchar(255)
-Time datetime
So an entry might look like this
433275 | 97 | MyLocation | OK | 2013-08-20 13:05:54
My question is, if I'm expecting 5 minute interval data from each of my sites, how can I determine how long a site has been down?
Example, if MyLocation didn't send in the 5 minute interval data from 13:05:54 until 14:05:54 it would've missed 60 minutes worth of intervals, how could I find this downtime and report on it easily?
Thanks,
*Disclaimer: I'm assuming that your time column determines the order of the entries in your table and that you can't easily (and without heavy performance loss) self-join the table on auto_increment column since it can contain gaps.*
Either you create a table containing simply datetime values and do a
FROM datetime_table d
LEFT JOIN your_table y ON DATE_FORMAT(d.datetimevalue, '%Y-%m-%d %H:%i:00') = DATE_FORMAT(y.`time`, '%Y-%m-%d %H:%i:00')
WHERE y.some_column IS NULL
(date_format() function is used here to get rid of the seconds part in the datetime values).
Or you use user defined variables.
SELECT * FROM (
SELECT
y.*,
TIMESTAMPDIFF(MINUTE, #prevDT, `Time`) AS timedifference
#prevDT := `Time`
FROM your_table y ,
(SELECT #prevDT:=(SELECT MIN(`Time`) FROM your_table)) vars
ORDER BY `Time`
) sq
WHERE timedifference > 5
EDIT: I thought you wanted to scan the whole table (or parts of it) for rows where the timedifference to the previous row is greater than 5 minutes. To check for a specific ID (and still having same assumptions as in the disclaimer) you'd have to do a different approach:
SELECT
TIMESTAMPDIFF(MINUTE, (SELECT `Time` FROM your_table sy WHERE sy.ID < y.ID ORDER BY ID DESC LIMIT 1), `Time`) AS timedifference
FROM your_table y
WHERE ID = whatever
EDIT 2:
When you say "if the ID is currently down" is there already an entry in your table or not? If not, you can simply check this via
SELECT TIMESTAMPDIFF(MINUTE, NOW(), (SELECT MAX(`Time`) FROM your_table WHERE ID = whatever));
So I assume you are going to have some sort of cron job running to check this table. If that is the case you can simply check for the highest time value for each id/location and compare it against current time to flag any id's that have a most recent time that is older than the specified threshold. You can do that like this:
SELECT id, location, MAX(time) as most_recent_time
FROM Historical
GROUP BY id
HAVING most_recent_time < DATE_SUB(NOW(), INTERVAL 5 minutes)
Something like this:
SELECT h1.ID, h1.location, h1.time, min(h2.time)
FROM Historical h1 LEFT JOIN Historical h2
ON (h1.ID = h2.ID AND h2.CID > h1.CID)
WHERE now() > h1.time + INTERVAL 301 SECOND
GROUP BY h1.ID, h1.location, h1.time
HAVING min(h2.time) IS NULL
OR min(h2.time) > h1.time + INTERVAL 301 SECOND

MySQL: Select corresponding row for maximum value grouped by date

I have a table with hourly temperatures:
id timestamp temperature
I want to select the highest temperature AND the corresponding timestamp for each day.
select max(temperature), timestamp from table group by date(from_unixtime(timestamp))
does not work because it always returns the timestamp of the first row (but I need the timestamp from the row with the highest temperature).
Any suggestions would be greatly appreciated.
Try this one....
select max(temperature), timestamp from temp group by UNIX_TIMESTAMP(date(timestamp));
Use a sub query like this;
select * from temp WHERE temperature=(select min(temperature) from temp)
Select the max temperature for each date, and then put that inside a join back to the table on the temperature and date, which will allow you to select the rows that match for temperature and date. A join will be faster than a subquery in most situations, and you can't always group inside a subquery, anyway.
Use date() to get the date part from the timestamp, and from_unixtime() will get a mySQL timestamp from a unix timestamp stored as either a string or an integer.
SELECT temperature, timestamp
FROM temp t
JOIN (
SELECT date(from_unixtime(timestamp)) as dt,
max(temperature) as maxTemp
FROM temp
GROUP BY date(from_unixtime(timestamp))
) m ON (
t.temperature = m.maxTemp AND
date(from_unixtime(t.timestamp)) = m.dt
)
However, I would suggest changing the table to store the timestamp as timestamp instead of varchar or int, and doing the conversion once when the data is inserted, instead of having to put it throughout the query. It will make things easier to read and maintain in the long term. Here's the same query if you change timestamp to be an actual timestamp:
SELECT temperature, timestamp
FROM temp t
JOIN (
SELECT date(timestamp) as dt,
max(temperature) as maxTemp
FROM temp
GROUP BY date(timestamp)
) m ON (
t.temperature = m.maxTemp AND
date(t.timestamp) = m.dt
)
Just a little easier to read, and probably faster, depending on how much data you have. You could also write that with an implicit join, which might be easier to read still. Just depends on your taste.
SELECT temperature, timestamp
FROM temp t, (
SELECT date(timestamp) as dt,
max(temperature) as maxTemp
FROM temp
GROUP BY date(timestamp)
) m
WHERE t.temperature = m.maxTemp
AND date(t.timestamp) = m.dt

MySQL - How to select rows with the min(timestamp) per hour of a given date

I have a table of production readings and need to get a result set containing a row for the min(timestamp) for EACH hour.
The column layout is quite simple:
ID,TIMESTAMP,SOURCE_ID,SOURCE_VALUE
The data sample would look like:
123,'2013-03-01 06:05:24',PMPROD,12345678.99
124,'2013-03-01 06:15:17',PMPROD,88888888.99
125,'2013-03-01 06:25:24',PMPROD,33333333.33
126,'2013-03-01 06:38:14',PMPROD,44444444.44
127,'2013-03-01 07:12:04',PMPROD,55555555.55
128,'2013-03-01 10:38:14',PMPROD,44444444.44
129,'2013-03-01 10:56:14',PMPROD,22222222.22
130,'2013-03-01 15:28:02',PMPROD,66666666.66
Records are added to this table throughout the day and the source_value is already calculated, so no sum is needed.
I can't figure out how to get a row for the min(timestamp) for each hour of the current_date.
select *
from source_readings
use index(ID_And_Time)
where source_id = 'PMPROD'
and date(timestamp)=CURRENT_DATE
and timestamp =
( select min(timestamp)
from source_readings use index(ID_And_Time)
where source_id = 'PMPROD'
)
The above code, of course, gives me one record. I need one record for the min(hour(timestamp)) of the current_date.
My result set should contain the rows for IDs: 123,127,128,130. I've played with it for hours. Who can be my hero? :)
Try below:
SELECT * FROM source_readings
JOIN
(
SELECT ID, DATE_FORMAT(timestamp, '%Y-%m-%d %H') as current_hour,MIN(timestamp)
FROM source_readings
WHERE source_id = 'PMPROD'
GROUP BY current_hour
) As reading_min
ON source_readings.ID = reading_min.ID
SELECT a.*
FROM Table1 a
INNER JOIN
(
SELECT DATE(TIMESTAMP) date,
HOUR(TIMESTAMP) hour,
MIN(TIMESTAMP) min_date
FROM Table1
GROUP BY DATE(TIMESTAMP), HOUR(TIMESTAMP)
) b ON DATE(a.TIMESTAMP) = b.date AND
HOUR(a.TIMESTAMP) = b.hour AND
a.timestamp = b.min_date
SQLFiddle Demo
With window function:
WITH ranked (
SELECT *, ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp) rn
FROM source_readings -- original table
WHERE date(timestamp)=CURRENT_DATE AND source_id = 'PMPROD' -- your custom filter
)
SELECT * -- this will contain `rn` column. you can select only necessary columns
FROM ranked
WHERE rn=1
I haven't tested it, but the basic idea is:
1) ROW_NUMBER() OVER(PARTITION BY HOUR(timestamp) ORDER BY timestamp)
This will give each row a number, starting from 1 for each hour, increasing by timestamp. The result might look like:
|rest of columns |rn
123,'2013-03-01 06:05:24',PMPROD,12345678.99,1
124,'2013-03-01 06:15:17',PMPROD,88888888.99,2
125,'2013-03-01 06:25:24',PMPROD,33333333.33,3
126,'2013-03-01 06:38:14',PMPROD,44444444.44,4
127,'2013-03-01 07:12:04',PMPROD,55555555.55,1
128,'2013-03-01 10:38:14',PMPROD,44444444.44,1
129,'2013-03-01 10:56:14',PMPROD,22222222.22,2
130,'2013-03-01 15:28:02',PMPROD,66666666.66,1
2) Then on the main query we select only rows with rn=1, in other words, rows that has lowest timestamp in each hourly partition (1st row after sorted by timestamp in each hour).