I am trying to write a trigger that would simplify logging changes when a record is updated. I have a stored procedure that does an INSERT to a logging table called log_update and a trigger that does the job for 1 field:
DROP TRIGGER IF EXISTS `parents_update`;
DELIMITER $$
CREATE TRIGGER `parents_update` AFTER UPDATE ON `parents`
FOR EACH ROW
BEGIN
IF ( NEW.motherLastName != OLD.motherLastName ) THEN
CALL log_update( 'parent', NEW.id, 4, CONCAT( OLD.motherLastName, ' > ', NEW.motherLastName ) );
END IF;
END;
$$
DELIMITER ;
Is it a way to make this more generic like provide list of fields:
( 'motherFirstName', 'motherLastName', 'fatherFistName', .... )
and loop through this list with a parameter for the single IF statement?
Edit:
I come up with such loop:
DROP TRIGGER IF EXISTS `parents_update`;
DELIMITER $$
CREATE TRIGGER `parents_update` AFTER UPDATE ON `parents`
FOR EACH ROW
BEGIN
DECLARE _fieldName VARCHAR(25);
DECLARE done INT DEFAULT FALSE;
DECLARE fieldsCursor CURSOR FOR SELECT fieldName FROM log_fields WHERE tableName = 'parents';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN fieldsCursor;
the_loop : LOOP
FETCH fieldsCursor INTO _fieldName;
IF done THEN
LEAVE the_loop;
END IF;
-- _fieldName will contain values such 'motherLastName'
IF ( NEW ( _fieldName ) != OLD ( _fieldName ) ) THEN
CALL log_update( 'parent', NEW.id, 4, CONCAT( OLD ( _fieldName ), ' > ', NEW ( _fieldName ) ) );
END IF;
END LOOP the_loop;
CLOSE fieldCursor;
END;
$$
DELIMITER ;
where table log_fields will contain fields to check. Now I am facing the problem of how to access the NEW. or OLD. property if the field name is in a variable.
I would say you can use prepared statements to achieve it, but unfortunately it is not supported in triggers.
You can read more about it here: http://dev.mysql.com/doc/refman/5.1/en/stored-program-restrictions.html OR answer here: Alternative to using Prepared Statement in Trigger with MySQL
which mean you can't create dynamic SQL query in your trigger the same applied to NEW. or OLD. variables dinamic build, so the only way is create separate triggers for each table with listed all column names one by one
Related
I'm trying to assign multiple values in a variable and execute a query using it. For example below:
SET #ledger = "'Cash','Special Offer'";
SELECT `_ledger` FROM `acc_ledger` WHERE `_ledger` IN(#ledger);
But this doesn't work as planned. Is there a way to define multiple values in a variable? If yes, how? If no, can I have a suggestion on how to tackle this issue?
You can pass multiple values with comma separated and then split those variables int table and perform a join
create function to split comma separated parameter
DELIMITER $$
DROP FUNCTION IF EXISTS `SPLIT_STR` $$
CREATE FUNCTION SPLIT_STR(id_list VARCHAR(500), delimeter VARCHAR(10), position INT)
RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(id_list, delimeter, position),
LENGTH(SUBSTRING_INDEX(id_list, delimeter, position - 1)) + 1),
delimeter, '');
END$$
DELIMITER ;
call SPLIT_STR function from query
SET #ledger = "Cash,Special Offer";
CREATE TEMPORARY TABLE IF NOT EXISTS `selected_types` (type varchar(50));
#inserting splitted values to temp table
simple_loop: LOOP
SET indx=indx+1;
SET str=SPLIT_STR(x_id_list,',',indx);
IF str='' THEN
LEAVE simple_loop;
END IF;
INSERT INTO selected_types VALUES(str);
END LOOP simple_loop;
#filter with temp table
SELECT `_ledger` FROM
`acc_ledger` led
inner join selected_types tmp on tmp.type = led._ledger;
I have a database where whenever residential address update in user table I want it to store in history table of user. For that I'm trying to write triggers but failing miserably in phpmyadmin. Also it's not giving me proper reason why so I can correct it. This is what I have done so far.
DROP TRIGGER IF EXISTS `record_history`;
CREATE TRIGGER `record_history` AFTER UPDATE ON `s_user`
FOR EACH ROW
BEGIN
DECLARE date_current datetime;
DECLARE residential_address varchar(1000);
SET #date_current = NOW();
SET #residential_address = NEW.residential_address;
IF (#residential_address <> OLD.residential_address AND #residential_address != "" AND #residential_address IS NOT NULL) THEN
INSERT INTO history_residential_address (`s_u_id`, `residential_address`, `status`, `date_added`, `date_updated`) VALUES
(OLD.s_u_id, #residential_address, 1, #date_current, #date_current);
END IF;
END;
delimiter ;
A cleaner version of your code
DROP TRIGGER IF EXISTS `record_history`;
delimiter $$
CREATE TRIGGER `record_history` AFTER UPDATE ON `s_user`
FOR EACH ROW
BEGIN
IF (new.residential_address <> OLD.residential_address AND new.residential_address <> "" AND new.residential_address IS NOT NULL) THEN
INSERT INTO history_residential_address (`s_u_id`, `residential_address`, `status`, `date_added`, `date_updated`) VALUES
(OLD.s_u_id, new.residential_address, 1, now(), now());
END IF;
END $$
delimiter ;
If you are still having problems please add sample data from s_user as text to the question.
I am using version 5.0 of mysql.
I'm trying to create a trigger to check if one entry(name of Food) exists in the other table.
I´ve done this:
delimiter //
CREATE TRIGGER verifyExists BEFORE INSERT ON Sold
FOR EACH ROW
BEGIN
IF NEW.nameF not in (
select A.nameF
From Available D
where (NEW.nameF = A.nameF and NEW.nameR = A.nameR)
)
END IF;
END;
//
delimiter ;
this doesen't work, why?
You have a couple of errors:
delimiter //
CREATE TRIGGER verifyExists BEFORE INSERT ON Sold
FOR EACH ROW
BEGIN
IF NEW.nameF not in (
select A.nameF
From Available A -- CHANGED THE ALIAS TO A
where (NEW.nameF = A.nameF and NEW.nameR = A.nameR)
) THEN -- MISSING THEN
CALL `Insert not allowed`;
END IF;
END;
//
delimiter ;
sqlfiddle demo
If you could use SIGNAL, it is the best way, but since it was only introduced in mysql 5.5, you will have to do it by other route. One way is to call a non existant function, like showed above. From this answer
My first time using triggers. Can anyone please explain why this trigger won't work? The error I'm getting is inconclusive (error near '' at line 5)
create trigger queue after update on downloads
for each row
begin
if NEW.completed = 1 then
insert into s_queue ( website_id ) values ( NEW.website_id );
end if;
end;
You need to change the delimiter from ; to something else, before defining any stored procedure/functions or triggers.
delimiter ||
create trigger queue after update on downloads
for each row
begin
if NEW.completed = 1 then
insert into s_queue ( website_id ) values ( NEW.website_id );
end if;
end||
delimiter;
I have created a procedure and ran it, but it is showing some syntax probem, can you help me?
My procedure is as:
**DELIMITER $$
CREATE PROCEDURE TestAdd(
in mODE varchar(10),
in Id int,
in AttName varchar(10),
in AttValues Varchar(10)
)
IF EXISTS (SELECT * FROM AttTable WHERE id=Id) THEN
SET Mode='Modify'
ELSE
SET Mode='Add'
Start Transaction
BEGIN
IF (mODE='Add') THEN
insert into atttable values (Id, AttName, AttValue);
ELSE (if Mode='Modify') then
update AttTable set AttName=AttName, AttValue= AttValue where Id=Id;
END IF
END
$$
Delimiter ;**
You need a BEGIN right after the parameter list at the beginning, and a matching END at the end of the procedure:
create procedure TestAdd(blah...)
BEGIN
...
END$$
Your first IF call is missing both THEN and END IF:
if exists ( select * from AttTable where id=Id) THEN
set...
ELSE
set...
END IF
Each of the statements needs to be terminated with a ;
set Mode='Modify';
set Mode='Add';
Start Transaction;