Deleting row on trigger before insert, with on duplicate update - mysql

Situation
I am saving modifications done on users' profiles (for a logging purpose).
I am using this query to insert/update in a :
INSERT INTO infos_update (username, date_modif, column_name, old_value, new_value)
VALUES ('johnsmith', CURDATE(), 'department', 'Management', 'IT/IS')
ON DUPLICATE KEY UPDATE new_value='IT/IS, date_modif=CURDATE()
The primary key is composed of date_modif, username, column_name, where date is a date and not a datetime.
Goal
I want to use a trigger to avoid logging values that did not changed (where old_value and new_value are equals)
delimiter //
CREATE TRIGGER before_insert_infos_update
BEFORE INSERT ON infos_update FOR EACH ROW
BEGIN
IF NEW.old_value = NEW.new_value THEN
DELETE FROM infos_update
WHERE infos_update.username= NEW.username
AND infos_update.date_modif = NEW.date_modif
AND infos_update.column_name = NEW.column_name;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Values are the same';
END IF;
END\\`
It prevents duplicates on initial insert, but when the row is already inserted, on duplicate key update can still update rows with duplicate old and new values; even when simply deleting the row before the update with that trigger

Related

INSERT INTO... ON DUPLICATE KEY UPDATE ... IF

I'm stuck on this one INSERT INTO for my school assignment.
INSERT INTO leaderboardeasy VALUES("Patrik", 15.44, 2021-04-24)
ON DUPLICATE KEY UPDATE IF(15.44 < Ido) Ido=15.44, Datum=2021-04-24
The 15.44 is a PHP variable.Basically I want insert into the table, if it not exists, and if it exists, and if the PHP variable(in this case 15.44 is smaller than the corresponding row(Ido) ) then I want to update the Ido, and Datum(current date) of the duplicate key.
What is the problem with my query?
you have a basic problem that dates have to be in single qiotes.
the if statement is not like mysql work,.
But i don't know if that reaöly makes what you want.
Because this would only run when Patrick is a primary key or a unique
INSERT INTO leaderboardeasy VALUES("Patrik", 15.44, '2021-04-24')
ON DUPLICATE KEY UPDATE Ido = IF(15.44 < Ido,15.44,Ido) , Datum=VALUES(Datum)
Better is a trigger
CREATE TRIGGER before_leaderboardeasy_insert
BEFORE INSERT
ON leaderboardeasy FOR EACH ROW
BEGIN
IF NEW.Ido > 15.44 THEN
SET NEW.Ido = 15.44;
END IF;
END $$
DELIMITER ;
If I understood you correctly your goal for the if statement is if the IF condition is met to update ido and datum to the given values, and otherwise not to update them and keep them intact. If this is the case:
INSERT INTO leaderboardeasy
VALUES("Patrik", 15.44, '2021-04-24')
ON DUPLICATE KEY UPDATE
`Ido` = CASE
WHEN (15.44 < `Ido`) THEN 15.44
ELSE `Ido`
END,
`Datum` = CASE
WHEN (15.44 < `Ido`) THEN '2021-04-24'
ELSE `Datum`
END

IF NOT EXISTS in mysql showing syntax error

I am trying to convert this tsql to mysql but showing error need help
CREATE PROCEDURE FormAdd
#formName varchar(MAX)
AS
IF NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=#formName)
BEGIN
INSERT INTO tbl_Form
(formName)
VALUES
(#formName)
SELECT ##identity
END
ELSE
BEGIN
SELECT '-1'
END
mysql
CREATE PROCEDURE FormAdd
(p_formName varchar(500) )
begin
INSERT INTO tbl_Form (formName)
VALUES (p_formName)
where NOT EXISTS(SELECT * FROM tbl_Form WHERE formName=p_formName) ;
SELECT Last_insert_id() as returnvalue ;
SELECT '-1' ;
end
Your attempt was syntactically invalid because logically, an INSERT statement cannot contain a WHERE clause since it does not act on existing rows.
If the purpose is to insert only if the value for p_formname is not already present, then an appropriate step would be to define a unique index on that column first. Then, construct your procedure to attempt the insert and inspect the ROW_COUNT() value to see if one was inserted and act accordingly, returning -1 if not to adapt your existing T-SQL procedure.
First create the unique index on p_formname:
ALTER TABLE tbl_Form ADD UNIQUE KEY `idx_formName` (`formName`);
Then your procedure should use INSERT INTO...ON DUPLICATE KEY UPDATE to attempt to insert the row. Per the documentation, the value of ROW_COUNT() will be 0 if a new row was not inserted or 1 if it was.
CREATE PROCEDURE FormAdd (p_formName varchar(500))
BEGIN
/* Attempt the insert, overwrite with the same value if necessary */
INSERT INTO tbl_Form (formName) VALUES (p_formName) ON DUPLICATE KEY UPDATE formName = p_formName;
/* Return the LAST_INSERT_ID() for a new row and -1 otherwise */
SELECT
CASE
WHEN ROW_COUNT() = 1 THEN LAST_INSERT_ID()
ELSE -1
END AS returnValue;
END

Trigger to insert values from another table - Mysql

I did this to trigger when the temperature is higher or lower than the parameter set off an alarm. Ie automatically populates the fields of the table alarm.
Now I created a new row in the table alarms, the idRegisto which is foreign key, now I want that id be completed in accordance with the idRegisto other corresponding table.
Does anyone can help me please?
If you are not understanding the question I will try to clarify further.
Thank you.
------------TRIGGER-------------------
DELIMITER $$
create TRIGGER alerta
BEFORE INSERT ON registos
FOR EACH ROW
begin
Set #tempmax=0;
Set #tempmin=0;
Set #hummax=0;
select lim_inf_temp, lim_sup_temp into #tempmin, #tempmax from sensores where idSensor=NEW.idSensor;
Set #maxidAlarme=0;
if (CAST(NEW.Temperatura AS UNSIGNED)<#tempmin) then
SELECT MAX(idAlarme) into #maxidAlarme FROM alarmes;
SET #maxidAlarme=#maxidAlarme+1;
INSERT INTO alarmes(idAlarme,descricao_alarme) VALUES (#maxidAlarme,"high-temperature");
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme) VALUES (NEW.idSensor,#maxidAlarme,NOW());
end if;
if (CAST(NEW.Temperatura AS UNSIGNED)>#tempmax) then
SELECT MAX(idAlarme) into #maxidAlarme FROM alarmes;
SET #maxidAlarme=#maxidAlarme+1;
INSERT INTO alarmes(idAlarme,descricao_alarme) VALUES (#maxidAlarme,"lower temperature");
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme) VALUES (NEW.idSensor,#maxidAlarme,NOW());
end if;
DELIMITER ;
------------ER------------------------
You can use an "after insert trigger"
AFTER INSERT ON registos
And take the "New.IdRegistro" to use as foreign key when populating the alarmes table.
//EDIT:
using your code:
AFTER INSERT ON registos
FOR EACH ROW
begin
Set #tempmax=0;
Set #tempmin=0;
Set #hummax=0;
...
INSERT INTO alarmes(idAlarme,descricao_alarme,idRegistro) VALUES (#maxidAlarme,"lower temperature",New.IdRegistro);
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme) VALUES (NEW.idSensor,#maxidAlarme,NOW());
...
I assume here that IdRegistro is a primary key (that will be autogenarated by your application or via autoincrement) of the registro table.
Register->if value higher/lower threshold -> trigger alarm -> insert sensores_tem_alarmes

Trigger to return duplicate error in MySQL and to affect the INSERT INTO..... ON DUPLICATE KEY UPDATE

I am having a challenge with MySQL. As you know MySQL does not consider NULL as a duplicate value in the unique indexes.
The problem here is that I have a table but I need to enforces that no similar data to be inserted "including NULL" into the following columns
(call_code_id, result_code_id, action_method, action_id, assign_to, assign_to_type)
You may suggest for me to add a unique index on those columns. The problem that the columns "assign_to" and "assign_id" allows NULL values. So based on MySQL definition of a unique columns the following 2 set of data are not Unique and will be allowed to be inserted
(call_code_id, result_code_id, action_method, action_id, assign_to, assign_to_type)
(1,1,'FINISH',NULL,5,2)
(1,1,'FINISH',NULL,5,2)
so even if I add a unique column, MySQL will allow those 2 rows to be inserted. But I need to prevent that for happening as my application consider those 2 rows duplicates.
I must say here that I update this table using stored procedure and I update the table using INSERT INTO ...... ON DUPLICATE KEY UPDATE statement.
My initial solution was to add a 2 triggers on that table. First trigger for insert and the other for update. Both trigger will return error code 1062 if a similar data was found before insert or update.
That did worked somewhat! But the new challenge is that the error code 1062 that is return by the trigger is not being utilized by the INSERT INTO ...... ON DUPLICATE KEY UPDATE statement. However, it is returning the 1062 error on the screen so it is finding the duplicates as it should. So when I execute the INSERT INTO ...... ON DUPLICATE KEY UPDATE statement I get the error 1062 returned on the screen, instead it should perform an update since I am asking it to update when duplicate records are found.
Here are my triggers syntax
DROP TRIGGER IF EXISTS `return_1062_on_duplicate_on_insert`;
DELIMITER //
CREATE TRIGGER `return_1062_on_duplicate_on_insert` BEFORE INSERT ON `inventory_engine_test`
FOR EACH ROW BEGIN
IF EXISTS(SELECT 1 FROM inventory_engine_test
WHERE call_code_id = NEW.call_code_id
AND result_code_id = NEW.result_code_id
AND action_method = NEW.action_method
AND IFNULL(action_id, 0) = IFNULL(NEW.action_id, 0)
AND IFNULL(assign_to, 0) = IFNULL(NEW.assign_to, 0)
AND assign_to_type = NEW.assign_to_type
AND NEW.engine_id IS NOT NULL) THEN
SIGNAL SQLSTATE '23000'
SET MYSQL_ERRNO = 1062,
TABLE_NAME = 'inventory_engine_test',
MESSAGE_TEXT = 'Duplicate key found - return_1062_on_duplicate_on_insert trigger';
END IF;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `return_1062_on_duplicate_on_update`;
DELIMITER //
CREATE TRIGGER `return_1062_on_duplicate_on_update` BEFORE UPDATE ON `inventory_engine_test`
FOR EACH ROW BEGIN
IF EXISTS(SELECT 1 FROM inventory_engine_test
WHERE call_code_id = NEW.call_code_id
AND result_code_id = NEW.result_code_id
AND action_method = NEW.action_method
AND IFNULL(action_id, 0) = IFNULL(NEW.action_id, 0)
AND IFNULL(assign_to, 0) = IFNULL(NEW.assign_to, 0)
AND assign_to_type = NEW.assign_to_type
AND NEW.engine_id IS NOT NULL) THEN
SIGNAL SQLSTATE '23000'
SET MYSQL_ERRNO = 1062,
TABLE_NAME = 'inventory_engine_test',
MESSAGE_TEXT = 'Duplicate key found - return_1062_on_duplicate_on_update trigger';
END IF;
END
//
DELIMITER ;
How can I get INSERT INTO ..... ON DUPLICATE KEY UPDATE to consider the error return by the trigger?
Thanks

PostgreSQL trigger updating secondary related table

I have two tables: table1 and table2, which triggers on inserts and on updates in the same function.
As you insert a value in table1 or table2 a value is inserted in table3, with the value table1.lastname || table1.firstname assigned to column3. The id obtained for the insert in table3 must be inserted into table1.id_table3.
CREATE OR REPLACE FUNCTION myschema.myfunction() RETURNS trigger AS
$BODY$
DECLARE
new_id_table_4 integer;
BEGIN
IF TG_OP = 'INSERT' THEN
IF TG_TABLE_NAME = 'table1' THEN
new_id_table_4 := 1;
ELSIF TG_TABLE_NAME = 'table2' THEN
new_id_table_4 := 2;
END IF;
INSERT INTO myschema.table3
(id, id_table4, name)
VALUES (DEFAULT, new_id_table_4, NEW.columnA||', '||NEW.columnB, TRUE, TRUE)
RETURNING id
INTO NEW.id_table3;
ELSIF TG_OP = 'UPDATE' THEN
IF OLD.columnA <> NEW.columnA OR OLD.columnB <> NEW.columnB THEN
UPDATE myschema.table3 SET
name = NEW.columnA||', '||NEW.columnB
WHERE id = NEW.id_cuenta;
END IF;
END IF;
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
ALTER FUNCTION myschema.myfunction() OWNER TO myuser;
CREATE TRIGGER add_table3record_table1
AFTER INSERT OR UPDATE
ON myschema.table1
FOR EACH ROW
EXECUTE PROCEDURE myschema.myfunction();
CREATE TRIGGER add_table3record_table2
AFTER INSERT OR UPDATE
ON myschema.table2
FOR EACH ROW
EXECUTE PROCEDURE myschema.myfunction();
The problem is that when I insert a new record into table1 or table2,
...RETURNING id INTO NEW.id_table3;
It does not seem to have any effect.
This is my first function/trigger ever, and I cannot find the error.
Thank you!
I'm pretty sure you can't update a row AFTER it has already been inserted just by setting NEW.foo = bar.
Either:
Perform an update on the table1 setting the new id_table3 value (which is going to recursively call you ON UPDATE trigger, so be careful), or
Use a BEFORE trigger instead of an AFTER.
Depending on how your foreign keys are set up between table1 and table3, the latter may or may not be an option.