I have two table source and target. Is it possible to perform following operation in single query?
If the row exists in both the source and target, UPDATE the target;
If the row only exists in the source, INSERT the row into the target;
If the row exists in the target but not the source,
DELETE the row from the target.
You can't do it all in one query, but you can do it all in one transaction if you are using a transactional store engine (like InnoDB). This might be what you want,
START TRANSACTION;
INSERT...;
DELETE...
UPDATE...;
COMMIT;
Related
If I understand correctly this code
START TRANSACTION;
SELECT field FROM table WHERE ... FOR UPDATE ; // single row
UPDATE table SET field = ... ;
COMMIT;
will lock the SELECT row until COMMIT.
But if I use MAX()
START TRANSACTION;
SELECT MAX(field) FROM table WHERE ... FOR UPDATE ; // whole table
UPDATE table SET field = ... ;
COMMIT;
will this code lock the whole table until COMMIT?
EDIT
Sorry, I have my question wrong.
Obviously above code will lock rows affected by WHERE. But it wouldn't lock the table. Meaning
INSERT INTO table() VALUES();
could still took place regardless of COMMIT.
That would mean the return value of
SELECT MAX(field) FROM table WHERE ... FOR UPDATE ;
is now no longer valid.
How to lock the table during transaction so neither INSERT nor UPDATE could took place before COMMIT?
It doesn't matter what you're selecting. FOR UPDATE locks all the rows that have to be examined to evaluate the WHERE clause. Otherwise, another transaction could change the columns that are mentioned there, so the later UPDATE would assign to different rows.
And since inserting a new row can change the value of MAX(field), it actually locks the entire table. When I try your example, and try to insert a new from another transaction, the second transaction blocks until I commit the first transaction.
Is there a way to create or drop tables in a trigger?
ex: If I have two tables, table1 and table2.
I want to create a trigger on table2, such that whenever table1 gets new inserted value or updates, drop current table2, and then create table3 (a new version of table2 that incorporates the changes in table1)
can I do such thing in Mysql? and what would be the syntax like if there is a way?
No.
https://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html says:
The trigger cannot use statements that explicitly or implicitly begin or end a transaction, such as START TRANSACTION, COMMIT, or ROLLBACK. (ROLLBACK to SAVEPOINT is permitted because it does not end a transaction.).
All DDL statements cause an implicit COMMIT.
Here's an example:
mysql> create trigger t after insert on mytable for each row
create table if not exists foo (i int);
ERROR 1422 (HY000): Explicit or implicit commit is not allowed in stored function or trigger.
Your use case sounds like a bad design. INSERT and UPDATE should affect data only, not have side-effects of changing the structure of your table.
I have MySQL database running with InnoDB engine. I have table which has columns id, nickname, score (so it's a scoreboard).
I need to check AFTER INSERT all rows and find similar record, if there is one delete old one.
USE 'database';
DELIMITER $$
CREATE TRIGGER tests_AINS AFTER INSERT ON tests FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
So how do I proceed?
It is possible to use a version control system with mysql databases?
Or, is there a version control system already implemented?
I want to say e.g.: SELECT foo FROM bar WHERE version = X
Whereeby version is a mysql internal colum with last update date.
Very late response... similar to Ruben's suggestion, I have setup triggers to update a version_control table to increment version number every time there is an INSERT, UPDATE & DELETE.
I laid out the steps on my site mradamfrancis.tumblr.com
** update **
I’ve decided to use triggers to assist with version control. Here’s how…
I have a table containing players, if there are changes (INSERT, DELETE, or UPDATE) I want to increment the version number in my version_control table.
This is how the version_control table looks:
version_id (key), table_name (varchar), version (integer)
I then create 3 triggers on the players table, one for INSERT, DELETE & UPDATE.
INSERT:
delimiter //
CREATE TRIGGER `player_table_INSERT` AFTER INSERT ON `players`
FOR EACH ROW BEGIN
UPDATE version_control SET version=version+1 WHERE table_name=’players’;
END;//
delimiter ;
DELETE:
delimiter //
CREATE TRIGGER `player_table_DELETE` AFTER DELETE ON `players`
FOR EACH ROW BEGIN
UPDATE version_control SET version=version+1 WHERE table_name=’players’;
END;//
delimiter ;
UPDATE:
delimiter //
CREATE TRIGGER `player_table_UPDATE` AFTER UPDATE ON `players`
FOR EACH ROW BEGIN
UPDATE version_control SET version=version+1 WHERE table_name=’players’;
END;//
delimiter ;
** I have additional SQL statements in the FOR EACH section of the trigger, hence I’ve used delimiter (1st line and last line) along with BEGIN & END.
You could also define extra tables for logging. For instance if you already have a table news, you can duplicate it as news_log. then add columns for logging data such as: modified date, action (update, delete, add) and so on.
next you define triggers on the original tables that will insert the data into your logging table. for instance when you update a record in you news table the news_log_trigger that you define is executed and a new record is inserted into new_log with the action value "UPDATE" and the current date as modified date.
for more info on mysql triggers:
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
In case you want to do this for every project you can problably write a generic stored procedure to do the actual logging. that way you can reuse it and you only have to define the triggers and logging tables.
I need determine each of this this 3 commands in trigger [UPDATE,DELETE,INSERT].For last 2 I do next:
IF EXISTS (SELECT * FROM inserted)
BEGIN
END
ELSE IF EXISTS (SELECT * FROM deleted)
BEGIN
END
How can I get updating rows?
Thanks.
Not exactly sure what you're trying to accomplish, but you can test if it's an UPDATE if both inserted (values after update) and deleted (values before update) exist. From the documentation:
The deleted table stores copies of the affected rows during DELETE
and UPDATE statements. During the execution of a DELETE or UPDATE
statement, rows are deleted from the trigger table and transferred to
the deleted table. The deleted table and the trigger table ordinarily
have no rows in common.
The inserted table stores copies of the affected rows during
INSERT and UPDATE statements. During an insert or update
transaction, new rows are added to both the inserted table and the
trigger table. The rows in the inserted table are copies of the new
rows in the trigger table.
Thus, if inserted exists but not deleted, it's an INSERT; if deleted exists but not inserted, it's a DELETE; if they both exist, it's an UPDATE.