Increment Time for every 10 Row using update in MySQL - mysql

need an mysql update query to increment time for every 10 row by 6 seconds with the first entry time starting from a specific date-time...
lets say 2015-12-08 00:00:00 is the timestamp i want for the first 10 entries,
next 10 entries should get
2015-12-08 00:00:06 ,
then the next 10-
2015-12-08 00:00:12
the next 10
2015-12-08 00:00:18
...and so on till last entry, the time has to increment by 6 seconds and accordingly the minutes and hours as it increases till the last entry
any idea how to make an update query for that?
PS: i dont have a unique id or value in the table in any column, the values may repeat. I would prefer an Update statement to use as i may have to change for other tables too,rather than triggers or Store procedure. I am using MySQL v7.02 SQLyog Enterprise

Hope the following statement can help:
select
#row_n := #row_n + 1 as row_no
, case when MOD(#row_n,10) =0 then #time:= ADDTIME(#time,'00:06') else #time end
from [your_table]
JOIN (SELECT #row_n := 0) r
JOIN (SELECT #time := now()) t
and example of update statement:
update tableA set dateCol=nestedTable.colB
from (
select
tableB.[some key]
, #row_n := #row_n + 1 as row_no
, (case when MOD(#row_n,10) =0 then #time:= ADDTIME(#time,'00:06') else #time end ) as colB
from tableB
JOIN (SELECT #row_n := 0) r
JOIN (SELECT #time := now()) t
) nestedTable
where tableA.[some key] = nestedTable.[some key]

Related

Find gaps in mysql Time

I have a table "channel_001" with timestamp column Time, and i did separate it by 10 minutes.
2013-01-01;00:10:04;
2013-01-01;00:20:00;
2013-01-01;00:30:02;
2013-01-01;00:40:04;
But there are missing datas. How can i detect a missing row? And then insert a row there?!
For example:
2013-01-01;00:10:04;
2013-01-01;00:20:00;
2013-01-01;00:30:02
2013-01-01;00:40:04;
2013-01-01;01:00:02;
then it would be missing:
2013-01-01;00:50:00;
I was thinking of using Join the table to itself, but im new in SQL and too much of a novice to finde the answere alone.
Any ideas?
You can find rows that don't have a "next" time with something like:
select c.*
from channel_001 c
where not exists (select 1
from channel_001 c2
where c2.timestamp > c.timestamp + interval 9 minute and
c2.timestamp < c.timestamp + interval 11 minute
);
If your table is large (tens of thousands of rows), you will probably want to use variables. The following code gets the previous timestamp:
select c.*,
(case when (#tmp := #prevts) is null then null
when (#prevts := timestamp) is null then null
else #tmp
end) as prev_timestamp
from channel_001 c cross join
(select #prevts := 0, #tmp := 0) vars
order by timestamp;
You can use this as a subquery to get gaps that are outside your range.

Group rows by time interval

i have a database with very much rows from a gps sender. The gps have 1 seconds delay to send next row to the database. So what i want to do is a web interface that shows travels, i dont want to show much rows, i want to group the rows to trips. So i want to do is a query who can declare a trip/travel by checking if its more then 14 minutes to next row, if it is then make a row of all rows before a give it a trip number, else add it to the "travel" collection.
Try this (example is at http://sqlfiddle.com/#!2/a0c86/39)
SELECT Trip, MIN(Date_Time), MAX(Date_Time)
FROM (
SELECT #Trip := IF(TIMESTAMPDIFF(MINUTE, #Date_Time, Date_Time) <= 20, #Trip, #Trip+1) AS TRIP
, logid
, #Date_Time := Date_time AS Date_Time
FROM gpslog
JOIN (SELECT #TRIP := 1, #Date_Time := null ) AS tmp
ORDER BY Date_Time) AS triplist
GROUP BY Trip

Mysql: update to create group of visit entries separated by no more than maxmium minutes

I have the following mysql table which records user visit times:
I'd like to update visit_id so that a "visit" is a group of entries for the same user where no entry is more than 20 minutes after the previous, and the visit_id for each entry is the visit_id of the first entry of that visit.
I hope that this example helps make it clear. After the update, the example table above should become:
I'm able to create an update which sets the visit_id to the visit_id of the previous entry for that user if the previous entry occurred less than 20 minutes before.
But I can't solve how to create a sql-only update to deal with the "cascading" effect, in other words, that the visit_id needs to find the earliest entry for that user_id which occurs before a 20-minute gap. It might be the visit_id of that entry (if it's the first of that visit), or the visit_id of previous entry, or of the previous-previous, or of the previous-previous-previous-previous, etc.
How could I write this update?
Try this query (but don't try it on production data, but rather on a copy of this data):
update tabb_after_update tabb,
(
select t.*,
( SELECT min( visit_id )
FROM tabb_after_update t1
WHERE t1.user_id = t.user_id
AND t1.time_of_visit <= t.time_of_visit
AND t1.time_of_visit >= subtime( t.time_of_visit, '00:20' )
) new_id
from tabb_after_update t
) tabb1
SET tabb.visit_id = tabb1.new_id
WHERE tabb.user_id = tabb1.user_id
AND tabb.visit_id = tabb1.visit_id
;
SQLFiddle demo --> http://www.sqlfiddle.com/#!2/caa08/1
------ EDIT -----
Another version that "joins gaps" into one group if gaps are <= 20 minutes.
set #last_uid = 0;
set #last_tm = '00:00';
set #last_vid = 0;
update tabb_after_update tabb,
(
select t.* ,
case when #last_uid = user_id
AND cast( #last_tm as time) >= subtime( time_of_visit, '00:20' )
then if( (#last_tm := time_of_visit ), #last_vid, #last_vid )
else
if( (#last_uid := user_id) +
(#last_vid := visit_id ) +
(#last_tm := time_of_visit ),
#last_vid, #last_vid )
end new_id
from tabb_after_update t
order by user_id, time_of_visit
) tabb1
SET tabb.visit_id = tabb1.new_id
WHERE tabb.user_id = tabb1.user_id
AND tabb.visit_id = tabb1.visit_id
;
SQLFiddle demo --> http://www.sqlfiddle.com/#!9/39f03/1
In this demo the user 1 has entries from 17:10 to 17:50 with "gaps" betwen records less than 20 minutes, and the query "combines" all these records into one group.

Catching latest column value change in SQL

How can I get the date for the latest value change in one column with one SQL query?
Possible database situation:
Date State
2012-11-25 state one
2012-11-26 state one
2012-11-27 state two
2012-11-28 state two
2012-11-29 state one
2012-11-30 state one
So result should return 2012-11-29 as latest change state. If I group by State value, I will get the date for first time I have that state in database.
The query will group the table on state and show the state and in the date field the latest date created of that state.
From the given input the output would be
Date State
2012-11-30 state one
2012-11-28 state two
This will get you the last state:
-- Query 1
SELECT state
FROM tableX
ORDER BY date DESC
LIMIT 1 ;
Encapsulating the above, we can use it to get the date just before the last change:
-- Query 2
SELECT t.date
FROM tableX AS t
JOIN
( SELECT state
FROM tableX
ORDER BY date DESC
LIMIT 1
) AS last
ON last.state <> t.state
ORDER BY t.date DESC
LIMIT 1 ;
And then use that to find the date (or the whole row) where the last change occurred:
-- Query 3
SELECT a.date -- can also be used: a.*
FROM tableX AS a
JOIN
( SELECT t.date
FROM tableX AS t
JOIN
( SELECT state
FROM tableX
ORDER BY date DESC
LIMIT 1
) AS last
ON last.state <> t.state
ORDER BY t.date DESC
LIMIT 1
) AS b
ON a.date > b.date
ORDER BY a.date
LIMIT 1 ;
Tested in SQL-Fiddle
And a solution that uses MySQL variables:
-- Query 4
SELECT date
FROM
( SELECT t.date
, #r := (#s <> state) AS result
, #s := state AS prev_state
FROM tableX AS t
CROSS JOIN
( SELECT #r := 0, #s := ''
) AS dummy
ORDER BY t.date ASC
) AS tmp
WHERE result = 1
ORDER BY date DESC
LIMIT 1 ;
I believe this is the answer:
SELECT
DISTINCT State AS State, `Date`
FROM
Table_1 t1
WHERE t1.`Date`=(SELECT MAX(`Date`) FROM Table_1 WHERE State=t1.State)
...and the test:
http://sqlfiddle.com/#!2/8b0d8/5
If you add another column 'changed datetime' you can fill this using an update trigger that inserts NOW(). If you query your table ordering on the changed column, it will endup first.
CREATE TRIGGER `trigger` BEFORE UPDATE ON `table`
FOR EACH ROW
BEGIN
SET ROW.changed = NOW();
END$$
Try this ::
Select
MAX(`Date`), state from mytable
group by state
If you had been using postgres, you could compare different rows in the same table using "LEAD .. OVER" I have not managed to find the same functionallity in mysql.
A bit hairy, but I think this will do:
select min(t1.date) from table_1 t1 where
(select count(distinct state) from table_1 where table_1.date>=t1.date)=1
Basically, this asks for the first time no changes in state is found for any later values. Be warned, it may be this query scales terribly for large data sets....
I think your best choice here are analytical functions. Try this - it should be OK performance-wise:
SELECT *
FROM test
WHERE my_date = (SELECT MAX (my_date)
FROM (SELECT MY_DATE
FROM ( SELECT MY_DATE,
STATE,
LAG (state) OVER (ORDER BY MY_DATE)
lag_val
FROM test
ORDER BY MY_DATE) a
WHERE state != lag_val))
In the inner select, the LAG function gets the previous value in the STATE column and in the outer select I mark the date of a change - those with lag value different than the current state value. And outside, I'm getting the latest date from those dates of a change... I hope that this is what you needed.
SELECT MAX(DATE) FROM YOUR_TABLE
Above answer doesn't seem to satisfy what OP needs.
UPDATED ANSWER WITH AFTER INSERT/UPDATE TRIGGER
DELCARE #latestState varchar;
DELCARE #latestDate date;
CREATE TRIGGER latestInsertTrigger AFTER INSERT ON myTable
FOR EACH ROW
BEGIN
IF OLD.DATE <> NEW.date THEN
SET #latestState = NEW.state
SET #latestDate = NEW.date
END IF
END
;
CREATE TRIGGER latestUpdateTrigger AFTER UPDATE ON myTable
FOR EACH ROW
BEGIN
IF OLD.DATE = NEW.date AND OLD.STATE <> NEW.STATE THEN
SET #latestState = NEW.state
SET #latestDate = NEW.date
END IF
END
;
You may use the following query to get the latest record added/updated:
SELECT DATE, STATE FROM myTable
WHERE STATE = #latestState
OR DATE = #latestDate
ORDER BY DATE DESC
;
Results:
DATE STATE
November, 30 2012 00:00:00+0000 state one
November, 28 2012 00:00:00+0000 state two
November, 27 2012 00:00:00+0000 state two
The above query results needs to be limitted to 2, 3 or n based on what you need.
Frankly it seems like you want to get max from both columns based on the data sample you have given. Assuming that your state only increases with the date. Only I wish if the state was an integer :D
Then union of two max sub queries on both columns would have solved it easily. Still a string manipulation regex can find what's the max in state column. Finally this approach needs limit x. However it still has lope hole. Anyway it took me sometime to figure your need out :$

MySQL update column with unrelated table data

I have two tables like this in mysql
a.cardnumber (unique)
a.position (numerical 3 digits or null)
a.serial
b.serial (unique)
b.lastused
I want to update any rows in "a" where position is above 600 AND "a.serial" is blank with any serial from "b.serial" where "b.lastused" is either null or more than 30 days ago. When the serial is copied into "a.serial" I want to update "b.lastused" with today's date so I know that the relevant "b.serial" has been used today.
There is no relation to the two tables apart from the serial and any serial from b can be used with any cardnumber in a.
I've tried this using my limited knowledge of mysql but I keep getting an error from my mysql desktop program to say I have an error in my query :(
Any help much appreciated!
I'm assuming here that you want to use a separate b.serial for each row to be updated in a. (This isn't specifically stated, but it seems to me to be most likely; please feel free to correct my assumption if it is wrong.)
I setup a small example. It wasn't clear what the datatypes for each of the columns, so I used INT where I wasn't sure. I used DATE datatype (rather than DATETIME) for lastused.
CREATE TABLE a (`cardnumber` VARCHAR(10) NOT NULL PRIMARY KEY, `position` INT, `serial` INT);
CREATE TABLE b (`serial` INT NOT NULL PRIMARY KEY, lastused DATE);
INSERT INTO a VALUES ('x0000',555,NULL),('x0001',700,123),('a1111',601,NULL),('a2222',602,NULL);
INSERT INTO b VALUES (100,'2012-07-15'),(101,NULL),(102,'2010-01-01'),(103,NULL),(104,NULL);
SELECT * FROM a;
SELECT * FROM b;
Based on the conditions you give, the rows with cardnumbers 'a1111' and 'a2222' should get updated, the other two rows should not (position <= 600, serial already assigned).
Before we run an UPDATE, we want to first run a SELECT that returns the rows to be updated, along with the values that will be assigned. Once we get that, we can convert that to a multi-table UPDATE statement.
SELECT a.cardnumber AS `a.cardnumber`
, a.position AS `a.position`
, a.serial AS `a.serial`
, b.serial AS `b.serial`
, b.lastused AS `b.lastused`
FROM (
SELECT #i := #i + 1 AS i
, aa.*
FROM a aa
JOIN (SELECT #i := 0) ii
WHERE aa.position > 600 /* assuming `position` is numeric datatype */
AND aa.serial IS NULL /* assuming 'blank' represented by NULL */
ORDER BY aa.cardnumber
) ia
JOIN (
SELECT #j := #j + 1 AS j
, bb.serial
, bb.lastused
FROM b bb
JOIN (SELECT #j := 0) jj
WHERE bb.lastused IS NULL
OR bb.lastused < DATE_ADD(NOW(),INTERVAL -30 DAY)
ORDER BY bb.serial
) jb
ON ia.i = jb.j
JOIN a ON a.cardnumber = ia.cardnumber
JOIN b ON b.serial = jb.serial
To convert that to an UPDATE, replace the SELECT ... FROM with UPDATE, and add a SET clause to assign new values to the tables.
UPDATE (
SELECT #i := #i + 1 AS i
, aa.*
FROM a aa
JOIN (SELECT #i := 0) ii
WHERE aa.position > 600
AND aa.serial IS NULL
ORDER BY aa.cardnumber
) ia
JOIN (
SELECT #j := #j + 1 AS j
, bb.serial
, bb.lastused
FROM b bb
JOIN (SELECT #j := 0) jj
WHERE bb.lastused IS NULL
OR bb.lastused < DATE_ADD(NOW(),INTERVAL -30 DAY)
ORDER BY bb.serial
) jb
ON ia.i = jb.j
JOIN a ON a.cardnumber = ia.cardnumber
JOIN b ON b.serial = jb.serial
SET a.serial = b.serial
, b.lastused = DATE(NOW())
-- 4 row(s) affected
You can run the queries for the inline views seperately (ia, jb) to verify that these are getting the rows you want to update.
The join from ia to a, and from jb to b, should be on the primary keys unique key.
The purpose of the ia and jb inline views is to get sequential numbers assigned to those rows so we can match them to each other.
The joins to a and b are to get back to the row in the original table, which is what we want to update.
(Obviously, some adjustments need to be made if serial is not an INT, or lastused is a DATETIME rather than a DATE.)
But this is an example of how I would go about doing the UPDATE you want to do (as best I understood it.)
NOTE: This approach works with MySQL versions that support subqueries. For MySQL 4.0, you would need to run this in steps, storing the results from the "ia" and "jb" inline views (subqueries) into actual tables. Then reference those tables in the query in place of the inline views. The ii and jj subqueries can be removed, and replaced with separate SELECT #i := 0, #j := 0 statement prior to the execution of the queries that reference these variables.
let me know if this works
Update table_a
set serial =
(
select b.serial from table_b b
where b.lastused = NULL
OR b.lastused < (current date - 30) limit 1
)
where cardnumber in
(
select a.cardnumber
from table_a a
where a.position > 600
and a.serial = NULL
)
update table_b b
set b.lastused = current date
where b.lastused = NULL
OR b.lastused < (current date - 30)