I wrote trigger that contains the following lines:
DECLARE is_journal TINYINT(1);
SET #is_journal := 1;
IF (is_journal IS NOT NULL) THEN
INSERT INTO `log` VALUES("is_journal is not null");
ELSE
INSERT INTO `log` VALUES("is_journal is null");
END IF;
And in my log table I always get as result
is_journal is null
Why does this happen?
As you are setting value to #is_journal. And comparing value of is_journal.
So first of all you have knowledge that both this thing are different.
So instead of
IF (is_journal IS NOT NULL) THEN line put
IF (#is_journal IS NOT NULL) THEN .
Related
I have table Demo:
create table Demo (
id int(10) auto_increment primary key,
text varchar(30) default null,
istrue boolean default false
);
I want create a update trigger such that:
When Update Demo set istrue = false where id = 1; (not "set text = ") -> normal update.
When Update Demo set text= 'abc' where id = 1; ("set text = ") -> SET NEW.text := concat(OLD.text,'#', NEW.text);
I have implemented trigger as follows:
DELIMITER $$
CREATE TRIGGER update_text
BEFORE update ON Demo
FOR EACH ROW
BEGIN
IF (exists(SELECT NEW.text)) THEN -- how to check NEW.text exists???
SET NEW.text := concat(OLD.text,'#', NEW.text);
END IF;
END$$
DELIMITER ;
But it isn't working! Please help. Thank You!!! (My English is not good. Hope everyone sympathized)
CREATE TRIGGER update_text
BEFORE update
ON Demo
FOR EACH ROW
SET NEW.text = CASE WHEN OLD.text <=> NEW.text
THEN NEW.text
ELSE CONCAT(OLD.text, '#', NEW.text)
END;
PS. Single-statement trigger - BEGIN-END and DELIMITER reassing not needed.
After the deep investigation I have found the way to detect that the field value was set in UPDATE statement.
However, I can't guarantee its reliability. I only check does the substring '`text`' is present in current query text - but there is a lot of situations when this check will give errorneous result, for example, wrong TRUE if this substring is a part of new value, or wrong FALSE if the fieldname is not wrapped with backticks. So be aware.
CREATE TRIGGER update_text
BEFORE update
ON demo
FOR EACH ROW
SET NEW.`text` = CASE WHEN LOCATE('`text`', ( SELECT info
FROM information_schema.processlist
WHERE id = CONNECTION_ID()
)
)
THEN CONCAT(OLD.`text`, '#', NEW.`text`)
ELSE NEW.`text`
END;
fiddle
I am trying to use an attribute from a 2nd table in the trigger of the 1st. To do this I am trying to load that value into a variable and then use it as a comparison.
However whenever I try and test the process the comparison answers false.
DELIMITER $$
create trigger evolve_persona before update on phantom_thieves
for each row begin
set #t := (select tier from persona where pname = old.persona);
if((new.persona != old.persona) and (select cast(#t as unsigned) = '1')) then
set
new.st = old.st+10, new.ma = old.ma+10, new.en= old.en+10, new.ag= old.ag+10,
new.lu= old.lu+20;
end if;
end$$
DELIMITER ;
I can see nothing wrong with your trigger but, this is somewhat more complicated as be written in a comment.
Make please following
SET #t = -1;
SELECT #t; -- returns -1
update phantom_thieves SET .....
SELECT #t; -should display at sometime 1
This seems to be the only problem that tier don't has the response 1 and with above, you can see what you get.
I want to add a trigger if name has update with "NEW_" string. Below is my current trigger but its working without checking the updated value contain "NEW_" . please advice
if user updates name from "Ann" to "NEW_Ann" trigger should work.
if user updates name from "Ann" to "Ann111" trigger shouldn't work
Code:
$this->execute("ALTER TABLE `users`
ADD COLUMN `date_` TIMESTAMP NULL DEFAULT NULL");
$this->execute("CREATE TRIGGER `update_user_deleted_date` BEFORE UPDATE ON `users` FOR EACH ROW BEGIN
IF (NEW.name!= OLD.name) THEN
SET NEW.date_deleted = NOW();
END IF;
END ;");
Use this:
CREATE TRIGGER update_user_deleted_date BEFORE UPDATE ON users
FOR EACH ROW BEGIN
IF (LOCATE('NEW_', NEW.name) != 0) THEN
SET NEW.date_deleted = NOW();
END IF;
END;
LOCATE('NEW_', NEW.name) != 0 means that the location of string "NEW_" is found
Since SQL does not have a FOR-EACH statement, how could we verify if there is a difference on each value from the OLD object to the NEW object in a AFTER UPDATE type TRIGGER without knowing the table columns [and table names]?
Example today:
CREATE TRIGGER `audit_events_ugly`
AFTER UPDATE ON `accounts`
FOR EACH ROW
BEGIN
DECLARE changes VARCHAR(8000);
IF OLD.user_name <> NEW.user_name THEN
SET changes = 'user_name from % to %';
END IF;
IF OLD.user_type <> NEW.user_type THEN
SET changes = CONCAT(changes, ', user_type from % to %');
END IF;
IF OLD.user_email <> NEW.user_email THEN
SET changes = CONCAT(changes, ', user_email from % to %');
END IF;
CALL reg_event(how_canI_get_tableName?, #user_id, changes);
-- and that can go on and on... differently for every table.
END;
Example as I wish it could be:
CREATE TRIGGER `audit_events_nice`
AFTER UPDATE ON `accounts`
FOR EACH ROW
BEGIN
DECLARE changes VARCHAR(8000);
DECLARE N INT DEFAULT 1;
FOREACH OLD, NEW as OldValue, NewValue
BEGIN
IF OldValue <> NewValue THEN
SET changes = CONCAT(changes, ', column N: % to %');
SET N = N + 1;
END IF;
CALL reg_event(how_canI_get_tableName?, #user_id, changes);
-- now I can paste this code in every table that is audited..
END;
Any Ideas? WHILE, FOREACH, ARRAYS...
I think you cannot do that directly in a for-loop at the trigger level.
However, you could use a script to generate the trigger code. You would need to re-generate it every time you add/remove a field to the table (usually not frequently).
I've an UPSERT trigger on a table that may update instead of inserting while doing insert operation. I've function doing insert on that table and returning id However it doesn't return an id when it updates instead of inserting. I want to get the id in both cases.
Trigger Code
perform 1 from tera_subject
where id = new.subject_id and owner = new.user_id;
if found then
return null;
else
select id into vote_id from tera_votes where
user_id = new.user_id and
subject_id = new.subject_id;
if not found then
return new;
else
-- raise notice 'vote_id: % ; vote: %',vote_id,new.vote;
if(tg_op = 'INSERT') then
begin
-- raise notice 'redirecting to update';
update tera_votes
set vote=new.vote
WHERE id = vote_id;
end;
elsif(tg_op = 'UPDATE') then
-- raise notice 'in update';
return new;
end if;
-- raise notice 'end of trigger %',tg_op;
return null;
end if;
end if;
end;
I don't think you'll manage to have anything “returned” by the trigger.
What you're doing inside is:
running update based on your conditions;
suppressing the INSERT statement that fired the trigger.
This means, that INSERT is terminated in an easy way (without exception), but it also means that it's impossible to provide you any details, as trigger functions do not return any values.
If you need to have the ID of the UPSERT-ed item, consider using a function that will always return you the ID, like this one.