How to fix duplicate key error while SET in MySQL - mysql

I was doing the following operation on a table:
UPDATE tname
SET cname = cname + INTERVAL 8 HOUR;
In the table, the cname column is for timestamps and set as a primary key. The operation is to add 8 hours to all the values of cname column.
But the operation gets an error message because of a duplicate key. I don't know how this could happen exactly but what I guess is that there was column 'cname' which has the values with 8 hours interval.
So when it tries to add 8 hours and write it, it gets the duplicate key error.
I have two questions:
If the operation gets the error, is the table inconsistent? I mean some rows are added with 8 hours and some rows are not?
How can I complete this operation without duplicate key error?

The update itself is creating the duplicate; depending on the order in which rows are processed, you might end up with a new value that conflicts with an existing one.
A common workaround is to use order by:
UPDATE tname
SET cname = cname + INTERVAL 8 HOUR
ORDER BY cname desc;
The query starts by updating the greatest date, then processes the rows in descending order, which prevents conflicts from happening.

Yes, unless you execute the query in a transaction, and use ROLLBACK; if there's an error.
You can check first whether there are any duplicates:
UPDATE tname AS t
JOIN (
SELECT COUNT(*) AS count
FROM tname AS t1
JOIN tname AS t2 ON t1.cname = t2.cname + INTERVAL 8 HOUR) as dups
SET t.cname = t.cname + INTERVAL 8 HOUR
WHERE dups.count = 0

Related

MySql - Add new row for every userId in the table

Below is the table i am trying to write a query for to add new rows for every user.
My question is how do i add a new row for every user? Which means for userId 2 I add AccId 4 and similarly for 7 and 8. Since there is no concept of for loop in sql, do i make use of while? If so, how to loop through the userIds since the IDs are not in equal increments?
something like this maybe:
Insert Into mytable (UserID, AccID)
Select UserID, max(accId)+1
From MyTable
Group By UserID
You can re-run it every time, you will create the next value.
Untested on a MySql server:
INSERT INTO MyTable ( ID, AccId )
SELECT MyValues.ID, MyValues.Espr1
FROM (SELECT MyTable.ID, Max([AccId]+1) AS Espr1
FROM MyTable
GROUP BY MyTable.ID) AS MyValues;
Basically we prefetch Id a AccId grouping the values of Id and grabbing the Max of AccId.
Then we add these rows to the main table. Repeating the query we will add the value 5 (AccId) and so on, always adding 1

INSERT IGNORE still inserting even with warning

I have this Mysql Query:
INSERT IGNORE INTO table1 (device_id, august) VALUES ((SELECT id from table2 where hostname='hostname'), 1)ON DUPLICATE KEY UPDATE august = august + 1;
For some hostnames the result from (SELECT id from table2 where hostname='hostname') is NULL and in that case I don't want anything inserted in the table and that's why I set the device_id column as primary key.
If I use IGNORE a warning is raised but the value august still gets incremented for a column with device_id = 0 (default value for that column) and I don't want that.
If I remove IGNORE an error is raised and nothing inserted. The problem is that I don't want to generate errors (and I don't want to use a try/catch).
Is there a way in MySQL so I can do that?
Thank you
I think having both IGNORE and ON DUPLICATE KEY UPDATE in the same query doesn't quite make sense.
I think this is what you want:
INSERT INTO table1 (device_id, august) (
SELECT id, 1 from table2 where hostname='hostname'
) ON DUPLICATE KEY UPDATE august = august + 1;

Cleaning old data after inserting the new data into table

First we start with empty table
rows = 0
Second we insert random rows let say 3400
rows = 3400
For the third time i count how many rows are in the table, then insert the new rows and after that delete rows <= from the count.
This logic only work for the first time. If that repeat the count will always be 3400 but the id will increase so it will not delete the rows
I cant use last inserted ID since the rows are random and I dont how many it will load.
// Update
"SELECT count(*) from table" - the total count so far
"INSERT INTO tab_videos_watched (id , name) values (id , name)" - this is random can be 3400 or 5060 or 1200
"DELETE FROM table WHERE idtable <= $table_count"
If id is auto incremented, then you should use like:
select max(id) from my_table;
Read this maxId into a variable and then use when issued a delete query like:
delete from my_table where id <= ?;
Replace query parameter with the last found maxId value.
Alternatively you can define a column last_inserted as datetime type.
Before next insertions, select it into a local variable.
select max(last_inserted) as 'last_inserted' from my_table;
And after insertions are made, use the last_inserted to delete records.
delete from my_table where last_inserted <= ?;
Replace query parameter with the last found last_inserted value.

Limiting table rows

How can I store only 10 rows in a MySQL table? The older rows should be deleted when a new row is added but only once the table has 10 rows.
Please help me
You could achieve this with an after insert trigger, delete the row where it is min date. e.g. DELETE FROM myTable WHERE myTimestamp = (SELECT MIN(myTimestamp) FROM myTable) but that could in theory delete multiple rows, depending on the granularity of your updates.
You could have an incrementing sequence, and always just delete the min of that sequence.
The question is why you'd want to do this though? It's a slightly unusual requirement.
A basic example (not validated/executed, I don't have mySQL on this particular machine) would look something like.
CREATE TRIGGER CycleOldPasswords AFTER INSERT ON UserPasswords FOR EACH ROW
set #mycount = SELECT COUNT(*) FROM UserPasswords up where up.UserId = NEW.UserId;
if myCount >= 10 THEN
DELETE FROM UserPasswords up where up.Timestamp = (SELECT min(upa Timestamp) FROM UserPasswords upa WHERE NEW.UserId = upa.UserId) AND NEW.UserId = up.UserId;
END
END;
You can retrieve the last inserted id when your first row is inserted, and store it in a variable. When 10 rows are inserted, delete the row having id < id of the first inserted record. Please try it.
first of all insert all values using your insert query
and then run this query
delete from table_name where (cond) order by id desc limit 10
must specify an id or time in one column

correlated subquery update

I have decided in my table that I no longer want to record start and finish times, but rather just a start time and a duration in minutes. How can I update my table so that my new column has its values inserted based on the existing data? my attempt below yields the error:
You can't specify target table 'lesson' for update in FROM clause
UPDATE lesson
SET duration =
(SELECT TIME_TO_SEC(TIMEDIFF(finish_time,start_time))/60
FROM lesson AS l
WHERE l.id = lesson.id)
You dont have to do that because your updating a column with values of other columns in the same row, do just:
UPDATE lesson
SET duration = TIME_TO_SEC(TIMEDIFF(finish_time,start_time))/60