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
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";
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.
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.
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)