Addition of time differences with where clause in mysql - php

I have a data table with hundreds of thousands of rows which represent requests to servers to get data. Each record has a timestamp, the server ID and a binary value (tinyint) of whether the server responded correctly. The query times are not constant.
I am trying to get a total amount of time that the server was deemed to be 'online' by adding up the times between the queries where the server was online (very highly preferable a mysql query).
Eg.
server | time | status
1 | 1/1/2012 11:00 online
1 | 1/1/2012 11:02 online
1 | 1/1/2012 11:05 offline
2 | 1/1/2012 11:10 online
1 | 1/1/2012 11:30 online
Time now: 11:40
Server 1 Online Time = 2+3+10 = 15 minutes
Is it possible to do this in mysql? I would much prefer it over getting all the rows to php and calculating it or averaging anything.

This could be done using UNIX timestamp conversion and variable assignment on a properly sorted row set. By "properly sorted" I mean the rows must be sorted by server, then by time. Here's how you could use variables to get the online time (interval) in seconds since the previous event for every row in your table (called server_status for the purpose of this answer):
SELECT
*,
#currenttime := UNIX_TIMESTAMP(`time`),
#lasttime := CASE
WHEN server <> #lastserver OR #laststatus = 'offline'
THEN #currenttime
ELSE #lasttime
END,
#currenttime - #lasttime AS seconds_online,
#lasttime := #currenttime,
#lastserver := server,
#laststatus := status
FROM
server_satus s,
(SELECT #lastserver := 0) x
ORDER BY
s.server,
s.`time`
As you can see, a temporary variable (#currenttime) is initialised with the UNIX timestamp equivalent of time, another one is used to hold the previous timestamp so that the difference between the two could be calculated. Other variables are used to remember the previous server ID and the previous status, so that, when necessary, the difference was returned as 0 (which is done for every row which records a server's first event as well as those that come after offline events).
You could now just group the result set produced by the above query, SUM() the seconds_online values and divide them by 60 to get minutes (if you aren't happy with seconds), like this:
SELECT
server,
SUM(seconds_online) DIV 60 AS minutes
FROM (
the query above
) s
Note, however, that the first query doesn't really calculate the servers' seconds spent online since their respective last events. That is, the current time might very well differ from that in any of the latest event records, and it wouldn't be taken into account, because the query calculates the seconds per row since the previous row.
One way to solve this would be to add one row per server containing the current timestamp and the same status as in the last record. So, instead of just server_status you would have the following as the source table:
SELECT
server,
`time`,
status
FROM server_status
UNION ALL
SELECT
s.server,
NOW() AS `time`,
s.status
FROM server_status s
INNER JOIN (
SELECT
server,
MAX(`time`) AS last_time
FROM server_status
GROUP BY
server
) t
ON s.server = t.server AND s.`time` = t.last_time
The left part of the UNION ALL just returns all rows from server_status. The right part first gets the last time per server, then joins the result set to server_status to get hold of the corresponding statuses, substituting time with NOW() along the way.
Now that the table is completed with the "fake" event rows reflecting the current time, you can apply the method used in the first query. Here's what the final query looks like:
SELECT
server,
SUM(seconds_online) DIV 60 AS minutes_online
FROM (
SELECT
*,
#currenttime := UNIX_TIMESTAMP(`time`),
#lasttime := CASE
WHEN server <> #lastserver OR #laststatus = 'offline'
THEN #currenttime
ELSE #lasttime
END,
#currenttime - #lasttime AS seconds_online,
#lasttime := #currenttime,
#lastserver := server,
#laststatus := status
FROM
(
SELECT
server,
`time`,
status
FROM server_status
UNION ALL
SELECT
s.server,
NOW() AS `time`,
s.status
FROM server_status s
INNER JOIN (
SELECT
server,
MAX(`time`) AS last_time
FROM server_status
GROUP BY
server
) t
ON s.server = t.server AND s.`time` = t.last_time
) s,
(SELECT #lastserver := 0) x
ORDER BY
s.server,
s.`time`
) s
GROUP BY
server
;
And you can try it (as well as play with it) at SQL Fiddle too.

Here is the sample table structure I created:
-- SQL EXAMPLE
CREATE TABLE IF NOT EXISTS `stack_test` (
`server` int(11) NOT NULL,
`rtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`status` tinyint(4) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `stack_test` (`server`, `rtime`, `status`) VALUES
(1, '2012-01-01 11:00:24', 1),
(1, '2012-01-01 11:02:24', 1),
(1, '2012-01-01 11:05:24', 0),
(2, '2012-01-01 11:10:24', 1),
(1, '2012-01-01 11:30:24', 1);
-- SQL EXAMPLE END
This is the PHP code:
<?php
$query = 'SELECT DISTINCT(`server`) `server` FROM stack_test';
$res = sql::exec($query); // replace with your function/method to execute SQL
while ($row = mysql_fetch_assoc($res)) {
$server = $row['server'];
$uptimes = sql::exec('SELECT * FROM stack_test WHERE server=? ORDER BY rtime DESC',$server);
$online = 0;
$prev = time();
$prev = strtotime('2012-01-01 11:40:00'); // just to show that it works given the example
while ($uptime = mysql_fetch_assoc($uptimes)) {
if ($uptime['status'] == 1) {
echo date('g:ia',$prev) . ' to ' . date('g:ia',strtotime($uptime['rtime'])) . ' = '.(($prev-strtotime($uptime['rtime']))/60).' mins<br />';
$online += $prev-strtotime($uptime['rtime']);
}
$prev = strtotime($uptime['rtime']);
}
echo 'Server '.$server.' is up for '.($online/60).' mins.<br />';
}
?>
This is the output I get:
11:40am to 11:30am = 10 mins
11:05am to 11:02am = 3 mins
11:02am to 11:00am = 2 mins
Server 1 is up for 15 mins.
11:40am to 11:10am = 30 mins
Server 2 is up for 30 mins.

Related

Insert into MySQL table if no row added within 5 minutes

I have a table which contains a column consisting of timestamps. I want to check if there is a new row within 5 minutes period of time. If not, then insert a new row or update the last row status column.
I tried something like this:
UPDATE table
SET status = 'offline'
WHERE CURRENT_TIMESTAMP() > ((SELECT MAX(dateandtime)) + INTERVAL 5 MINUTE)
or insert into ... but no success so far. I'm using PHP in WordPress if that matters.
I hope this helps you. If you want to add new row, you need to use INSERT command with selection like this...
INSERT INTO sessions(user_id, last_visit)
SELECT 1, CURRENT_TIMESTAMP
WHERE EXISTS (
SELECT 1
FROM sessions
WHERE user_id = 1
HAVING (MAX(last_visit) + INTERVAL 5 MINUTE) < CURRENT_TIMESTAMP
);
If you want to update status column, you need to use simple UPDATE
UPDATE sessions
SET status = 'offline'
WHERE (last_visit + INTERVAL 5 MINUTE) < CURRENT_TIMESTAMP;
Btw, you just need to have a last_visit column, and if it's less than now + 5 min, you already know that the user is offline. And you have to update this value on every authorized request with simple update like.
update users set last_visit = CURRENT_TIMESTAMP where id = ?;
So your User class will be have a function getStatus() like this:
public function getStatus() {
if ($this->lastVisit < (Carbon::now()->subMinutes(5))) {
return 'offline';
}
return 'online';
}
Assuming you have an auto-increment primary key, you can do this with replace:
replace into foo (id,dateandtime,status) values (
(select id from foo f where dateandtime > now()-interval 5 minute order by dateandtime desc limit 1),
now(),
# or if you want to preserve the current timestamp, replace the previous now() with:
#coalesce((select max(dateandtime) from foo f where dateandtime > now()-interval 5 minute), now()),
'offline'
);
This tries to find the id of the row to update, or uses null to trigger a new auto-increment id to be generated.
Note that replace is unsafe (may cause the source and replica to diverge) when using statement-based replication; in that case you would need a stored procedure, or in your code (in a transaction, to prevent a race condition) to do an update, and only if it updated 0 rows, do an insert.
fiddle fiddle

PHP / MySQL nth row with DATE_SUB, etc

So I have a table, I use to graph some data.
id, agcid, ooscount, date
Data is samples every 5 minutes for 18 objects
ID is auto increment, agcid represents the ID of the object, date is self explanitory and ooscount is an integer column.
I'm currently using this:
$sql2 = "SELECT ooscount, date
FROM ooscount
where agcid = '".$agcid."' AND date >= DATE_SUB(NOW( ),INTERVAL 7 HOUR)
order by date DESC";
Simple, yet effective, however I have an extremely large dataset which complicates the graphs.
I tried adding AND ooscount.id mod 3 = 0 to this however, the data sets on each agcid seemed very random, some had only a couple, others had 5x more than they should.
I then tried an approach like this:
$sql2 = "set #row:=-1;
SELECT ooscount.*
FROM
ooscount
INNER JOIN
(
SELECT id
FROM
(
SELECT #row:=#row+1 AS rownum, id
FROM
(
SELECT id, date, ooscount FROM ooscount where agcid = '".$agcid."' and date >= DATE_SUB(NOW( ),INTERVAL 12 HOUR) order by date DESC
) AS sorted
) as ranked
WHERE rownum % 3 = 0
) AS subset
ON subset.id = ooscount.id;";
It's commented out, forgive the //'s. However this approach while it works in phpMyAdmin, gives me this:
PHP Fatal error: Call to a member function fetch_assoc()
on a non-object in /var/www/khamlin/oosagc.php on line 145
Lastly, the portion of code to display this:
$result2 = $conn->query($sql2);
$rowsarray = "";
//var_dump($result2);
while ($row2 = $result2->fetch_assoc()) {
I believe the problem is that examples I've found don't expect multiple data sets on a single table, and thus ID would be incremental (ie: 1,2,3,4,5,6, etc), rather than ( 168006, 168023, 168041, 168060 ).
How would I go about changing this to suit my needs here?
Structure
CREATE TABLE IF NOT EXISTS `ooscount` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`agcid` int(3) NOT NULL,
`ooscount` int(10) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=168580 ;
````
Sample Data: https://jpst.it/1bfFt
Current Output: a data point of ooscount and date every 5 minutes (ie:
data: [{"ooscount":"4907","date":"2018-02-21 09:40:01"},{"ooscount":"4905","date":"2018-02-21 09:35:02"},{"ooscount":"4910","date":"2018-02-21 09:30:02"},{"ooscount":"4904","date":"2018-02-21 09:25:01"},{"ooscount":"4900","date":"2018-02-21 09:20:02"},{"ooscount":"4898","date":"2018-02-21 09:15:02"},{"ooscount":"4989","date":"2018-02-21 09:10:01"},{"ooscount":"5008","date":"2018-02-21 09:05:02"},{"ooscount":"4933","date":"2018-02-21 09:00:01"},{"ooscount":"4915","date":"2018-02-21 08:55:01"},{"ooscount":"4903","date":"2018-02-21 08:50:02"},{"ooscount":"4898","date":"2018-02-21 08:45:01"},{"ooscount":"4899","date":"2018-02-21 08:40:01"},{"ooscount":"4909","date":"2018-02-21 08:35:01"},{"ooscount":"4918","date":"2018-02-21 08:30:01"},{"ooscount":"4906","date":"2018-02-21 08:25:02"},{"ooscount":"4906","date":"2018-02-21 08:20:01"},{"ooscount":"4900","date":"2018-02-21 08:15:02"},{"ooscount":"4895","date":"2018-02-21 08:10:01"},{"ooscount":"4883","date":"2018-02-21 08:05:02"},{"ooscount":"4881","date":"2018-02-21 08:00:01"},{"ooscount":"4879","date":"2018-02-21 07:55:02"},{"ooscount":"4883","date":"2018-02-21 07:50:02"},{"ooscount":"4875","date":"2018-02-21 07:45:02"},{"ooscount":"4875","date":"2018-02-21 07:40:01"},{"ooscount":"4879","date":"2018-02-21 07:35:02"},{"ooscount":"4882","date":"2018-02-21 07:30:01"},{"ooscount":"4888","date":"2018-02-21 07:25:01"},{"ooscount":"4877","date":"2018-02-21 07:20:01"},{"ooscount":"4879","date":"2018-02-21 07:15:02"},{"ooscount":"4884","date":"2018-02-21 07:10:02"},{"ooscount":"4886","date":"2018-02-21 07:05:02"},{"ooscount":"4904","date":"2018-02-21 07:00:02"},{"ooscount":"4906","date":"2018-02-21 06:55:01"},{"ooscount":"4904","date":"2018-02-21 06:53:32"},{"ooscount":"4904","date":"2018-02-21 06:50:02"},{"ooscount":"4892","date":"2018-02-21 06:45:01"},{"ooscount":"4795","date":"2018-02-21 06:40:02"},{"ooscount":"4793","date":"2018-02-21 06:35:01"},{"ooscount":"4799","date":"2018-02-21 06:30:02"},{"ooscount":"4797","date":"2018-02-21 06:25:02"},{"ooscount":"4802","date":"2018-02-21 06:20:01"},{"ooscount":"4801","date":"2018-02-21 06:15:01"},{"ooscount":"4792","date":"2018-02-21 06:10:02"},{"ooscount":"4798","date":"2018-02-21 06:05:02"},{"ooscount":"4797","date":"2018-02-21 06:00:01"},{"ooscount":"4798","date":"2018-02-21 05:55:02"},{"ooscount":"4794","date":"2018-02-21 05:50:01"},{"ooscount":"4796","date":"2018-02-21 05:45:02"},{"ooscount":"4804","date":"2018-02-21 05:40:02"},{"ooscount":"4803","date":"2018-02-21 05:35:01"},{"ooscount":"4809","date":"2018-02-21 05:30:02"},{"ooscount":"4811","date":"2018-02-21 05:25:01"},{"ooscount":"4810","date":"2018-02-21 05:20:01"},{"ooscount":"4831","date":"2018-02-21 05:15:02"},{"ooscount":"4839","date":"2018-02-21 05:10:02"},{"ooscount":"4859","date":"2018-02-21 05:05:01"},{"ooscount":"4859","date":"2018-02-21 05:00:01"},{"ooscount":"4858","date":"2018-02-21 04:55:02"},{"ooscount":"4858","date":"2018-02-21 04:50:02"},{"ooscount":"4863","date":"2018-02-21 04:45:02"},{"ooscount":"4868","date":"2018-02-21 04:40:01"},{"ooscount":"4872","date":"2018-02-21 04:35:01"},{"ooscount":"4868","date":"2018-02-21 04:30:02"},{"ooscount":"4867","date":"2018-02-21 04:25:02"},{"ooscount":"4870","date":"2018-02-21 04:20:01"},{"ooscount":"4866","date":"2018-02-21 04:15:02"},{"ooscount":"4864","date":"2018-02-21 04:10:02"},{"ooscount":"4863","date":"2018-02-21 04:05:01"},{"ooscount":"4874","date":"2018-02-21 04:00:02"},{"ooscount":"4881","date":"2018-02-21 03:55:01"},{"ooscount":"4850","date":"2018-02-21 03:50:02"},{"ooscount":"4846","date":"2018-02-21 03:45:01"},{"ooscount":"4847","date":"2018-02-21 03:40:02"},{"ooscount":"4850","date":"2018-02-21 03:35:02"},{"ooscount":"4845","date":"2018-02-21 03:30:01"},{"ooscount":"4847","date":"2018-02-21 03:25:02"},{"ooscount":"4848","date":"2018-02-21 03:20:01"},{"ooscount":"4847","date":"2018-02-21 03:15:02"},{"ooscount":"4852","date":"2018-02-21 03:10:03"},{"ooscount":"4854","date":"2018-02-21 03:05:01"},{"ooscount":"4864","date":"2018-02-21 03:00:01"},{"ooscount":"4867","date":"2018-02-21 02:55:02"},{"ooscount":"4868","date":"2018-02-21 02:50:01"},{"ooscount":"4862","date":"2018-02-21 02:45:02"}],
The goal is to have less data points over the same amount of time.
I found a solution that works for me.
$sql2 = "SELECT *
FROM (
SELECT #row := #row +1 AS rownum, ooscount.*
FROM (
SELECT #row :=0) r, ooscount where agcid='".$agcid."' and date >= DATE_SUB(NOW( ),INTERVAL 12 HOUR)
) ranked
WHERE rownum %3 =1";

Single query that allows alias with it's own limit

I would like to better optimize my code. I'd like to have a single query that allows an alias name to have it's own limit and also include a result with no limit.
Currently I'm using two queries like this:
// ALL TIME //
$mikep = mysqli_query($link, "SELECT tasks.EID, reports.how_did_gig_go FROM tasks INNER JOIN reports ON tasks.EID=reports.eid WHERE `priority` IS NOT NULL AND `partners_name` IS NOT NULL AND mike IS NOT NULL GROUP BY EID ORDER BY tasks.show_date DESC;");
$num_rows_mikep = mysqli_num_rows($mikep);
$rating_sum_mikep = 0;
while ($row = mysqli_fetch_assoc($mikep)) {
$rating_mikep = $row['how_did_gig_go'];
$rating_sum_mikep += $rating_mikep;
}
$average_mikep = $rating_sum_mikep/$num_rows_mikep;
// AND NOW WITH A LIMIT 10 //
$mikep_limit = mysqli_query($link, "SELECT tasks.EID, reports.how_did_gig_go FROM tasks INNER JOIN reports ON tasks.EID=reports.eid WHERE `priority` IS NOT NULL AND `partners_name` IS NOT NULL AND mike IS NOT NULL GROUP BY EID ORDER BY tasks.show_date DESC LIMIT 10;");
$num_rows_mikep_limit = mysqli_num_rows($mikep_limit);
$rating_sum_mikep_limit = 0;
while ($row = mysqli_fetch_assoc($mikep_limit)) {
$rating_mikep_limit = $row['how_did_gig_go'];
$rating_sum_mikep_limit += $rating_mikep_limit;
}
$average_mikep_limit = $rating_sum_mikep_limit/$num_rows_mikep_limit;
This allows me to show an all-time average and also an average over the last 10 reviews. Is it really necessary for me to set up two queries?
Also, I understand I could get the sum in the query, but not all the values are numbers, so I've actually converted them in PHP, but left out that code in order to try and simplify what is displayed in the code.
All-time average and average over the last 10 reviews
In the best case scenario, where your column how_did_gig_go was 100% numeric, a single query like this could work like so:
SELECT
AVG(how_did_gig_go) AS avg_how_did_gig_go
, SUM(CASE
WHEN rn <= 10 THEN how_did_gig_go
ELSE 0
END) / 10 AS latest10_avg
FROM (
SELECT
#num + 1 AS rn
, tasks.show_date
, reports.how_did_gig_go
FROM tasks
INNER JOIN reports ON tasks.EID = reports.eid
CROSS JOIN ( SELECT #num := 0 AS n ) AS v
WHERE priority IS NOT NULL
AND partners_name IS NOT NULL
AND mike IS NOT NULL
ORDER BY tasks.show_date DESC
) AS d
But; Unless all the "numbers" are in fact numeric you are doomed to sending every row back from the server for php to process unless you can clean-up the data in MySQL somehow.
You might avoid sending all that data twice if you establish a way for your php to use only the top 10 from the whole list. There are probably way of doing that in PHP.
If you wanted assistance in SQL to do that, then maybe having 2 columns would help, it would reduce the number of table scans.
SELECT
EID
, how_did_gig_go
, CASE
WHEN rn <= 10 THEN how_did_gig_go
ELSE 0
END AS latest10_how_did_gig_go
FROM (
SELECT
#num + 1 AS rn
, tasks.EID
, reports.how_did_gig_go
FROM tasks
INNER JOIN reports ON tasks.EID = reports.eid
CROSS JOIN ( SELECT #num := 0 AS n ) AS v
WHERE priority IS NOT NULL
AND partners_name IS NOT NULL
AND mike IS NOT NULL
ORDER BY tasks.show_date DESC
) AS d
In future (MySQL 8.x) ROW_NUMBER() OVER(order by tasks.show_date DESC) would be a better method than the "roll your own" row numbering (using #num+1) shown before.

Display latest temperature by location quickly

The Table I have has temperatures, locations and datetime and other data that isn't currently used. Message is the temperature and locationmap is where the sensor is ie, lounge, kitchen, outside!)
Query :
SELECT
t1.*
FROM
temperatures t1
JOIN (
SELECT
locationmap
, MAX(timeof) AS timeof
FROM
temperatures
GROUP BY
locationmap
) AS t2
ON t1.locationmap = t2.locationmap AND t1.timeof = t2.timeof
WHERE
DATE(t1.timeof) BETWEEN DATE_SUB(CURDATE(), INTERVAL 5 MINUTE) AND CURDATE()";
Resulting PHP code to display current temperatures;
// Print out result
while($row = mysql_fetch_array($result)){
echo $row['locationmap']. " - ". $row['message']. " #". $row['timeof'];
echo "<br />";
}
Just want it to display the latest temperature for each location, which it currently does, but I was wondering if this the best optimised query for speed, as at the moment it takes 7secs to display results!? Mind u I have a slow server, but I'm the only user.
Thx.
FYI.
Can't say without table create statements, more information about indexes and storage engine
And please make your SQL code more readable in your PHP code, It's damn hard to read like this.
SELECT
t1.*
FROM
temperatures t1
JOIN (
SELECT
locationmap
, MAX(timeof) AS timeof
FROM
temperatures
GROUP BY
locationmap
) AS t2
ON t1.locationmap = t2.locationmap AND t1.timeof = t2.timeof
WHERE
DATE(t1.timeof) BETWEEN DATE_SUB(CURDATE(), INTERVAL 5 MINUTE) AND CURDATE()
The same query but more readable
And thanks for the minus 1, because i tryed to help...
This query should run sightly faster
SELECT
t1.locationmap
, t1.message
, t1.timeof
FROM
temperatures AS t1
JOIN (
SELECT
locationmap
, MAX(timeof) AS timeof
FROM
temperatures
GROUP BY
locationmap
) AS t2
ON t1.locationmap = t2.locationmap AND t1.timeof = t2.timeof
WHERE
DATE(t1.timeof) BETWEEN DATE_SUB(CURDATE(), INTERVAL 5 MINUTE) AND CURDATE()
And make sure you have a covering BTREE (if you use MyISAM or innodb indexes are already BTREE) index on locationmap, timeof and message (optional) (be sure you build the index like this)
Please note that inserts, updates and deleted run sightly slower because of the covering index.
So try to multiinsert to keep the speed up.

sql Runtime reports

I have a query which displays information from a table like this.
SELECT tag.label, inputs.input_raw, inputs.unix_timestamp, tag.inverted FROM inputs
JOIN tag
ON tag.tag_id = inputs.tag_id
WHERE (inputs.tag_id = 92084)
AND (inputs.date_time > dateadd(day,-1,getdate()))
ORDER BY date_time DESC
I would like to write a query which would do two things.
I need a count of every time input_raw switches from '0' to '1'.
I also need a total time of the pump running, using the unix_timestamp ie. when the input_raw = 1.
Does anyone have any ideas.
I would settle for an algorithm to use php to get the results I need but I've hit a brick wall and haven't been able to figure it out.
Thanks
EDIT: The table also contains a date_time field which matches the value of the unix_timestamp if there is a date_time method that can be used>
You want to use the Lead orLag function to compare the current result with either the previous or next. These functions, however, are introduced in SQL Server 2012.
With the help of Mr. pinaldave I managed to produce the following SQL Fiddle that counts every change from 0 to 1.
;WITH x AS
(
SELECT
1 AS ldOffset, -- equiv to 2nd param of LEAD
1 AS lgOffset, -- equiv to 2nd param of LAG
NULL AS ldDefVal, -- equiv to 3rd param of LEAD
NULL AS lgDefVal, -- equiv to 3rd param of LAG
ROW_NUMBER() OVER (ORDER BY unix_timestamp) AS row,
label,
input_raw,
unix_timestamp,
inverted
FROM inputs
)
SELECT
COUNT(1)
FROM x
LEFT OUTER JOIN x AS xLg
ON x.row = xLg.row + x.lgOffset
WHERE xLg.input_raw = 0 AND x.input_raw = 1;
You can use the same Lag function to calculate the difference between the current timestamp and the previous timestamp.
EDIT:
This SQL Fiddle should show how to get the total time the pump is running (you'll have to define running yourself. This query now assumes that going from 0 to 1 or staying 1 is running. You should also double check my timestamp calculations cause I've never used unix timestamps before.
;WITH x AS
(
SELECT
1 AS ldOffset, -- equiv to 2nd param of LEAD
1 AS lgOffset, -- equiv to 2nd param of LAG
NULL AS ldDefVal, -- equiv to 3rd param of LEAD
NULL AS lgDefVal, -- equiv to 3rd param of LAG
ROW_NUMBER() OVER (ORDER BY unix_timestamp) AS row,
label,
input_raw,
unix_timestamp,
inverted
FROM inputs
)
SELECT
SUM(DATEDIFF(mi,
DATEADD(ss, xLg.unix_timestamp,'01/01/1970'),
DATEADD(ss, x.unix_timestamp,'01/01/1970')))
FROM x
LEFT OUTER JOIN x AS xLg
ON x.row = xLg.row + x.lgOffset
WHERE
(xLg.input_raw = 0 AND x.input_raw = 1)
OR
(xLg.input_raw = 1 AND x.input_raw = 1);
EDIT 2:
I guess the easiest way to check for inverted is the change the WHEREclause to something like:
WHERE
(x.inverted = 1 AND xLg.input_raw = 0 AND x.input_raw = 1)
OR
(x.inverted = 0 AND xLg.input_raw = 1 AND x.input_raw = 0)

Categories