I'm trying to execute this query in a database through phpmyadmin
create trigger avoid_duplicated_sharing
before insert on sharingevents
for each row
begin
if ( select count(*) from sharingevents where shared_note_id = NEW.shared_note_id AND shared_to = NEW.shared_to > 0 ) then
delete from sharingevents where shared_note_id = NEW.shared_note AND shared_to = NEW.shared_to
END IF;
END
But phpmyadmin gives me the following error:
MySQL said: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'END IF' at line 7
Two questions:
What's wrong with my script?
After a BEFORE INSERT trigger, Will INSERT operation be performed? In case it doesn't I will have to remove INSERT INTO SharingEvents (SELECT * FROM NEW);
I solve it with the following code:
delimiter $$
create trigger avoid_duplicated_sharing
before insert on sharingevents
for each row
begin
if ( select count(*) from sharingevents where shared_note_id = NEW.shared_note_id AND shared_to = NEW.shared_to > 0 ) then
delete from sharingevents where shared_note_id = NEW.shared_note_id AND shared_to = NEW.shared_to;
end if;
END$$
The problem was the delimiter.
Even so, my trigger doesn't work. When the application inserts duplicated primary keys MySQL throws the following error:
#1442 - Can't update table 'sharingevents' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Use exists:
if (exists (select 1 from sharingevents where shared_note_id = new.shared_note_id AND shared_to = new.shared_to) > 0) then
insert into sharingevents (shared_note_id,shared_to,permission_level)
values (NEW.shared_note_id,NEW.shared_to,NEW.permission_level);
end if;
Or, better yet, add a unique index on sharingevents(shared_note-id, shared_to) and then use:
insert into sharingevents (shared_note_id, shared_to, permission_level)
values (NEW.shared_note_id, NEW.shared_to, NEW.permission_level)
on duplicate key update shared_note_id = values(shared_note_id);
This will ignore any updates where the pairs already exist in the table. No if required.
count(shared_note_id, shared_to) is invalid syntax. You can only put multiple column names inside COUNT() when you use count(DISTINCT ...). In your case, you don't need to put column names at all, just use COUNT(*) to count the number of rows matching the condition.
See count(*) and count(column_name), what's the diff? for more information about when you should put column names in COUNT()
Unfortunately, fixing the syntax errors won't really solve your problem, because you can't use a trigger to make a change to the same table. From the FAQ:
Can triggers access tables?
A trigger can access both old and new data in its own table. A trigger can also affect other tables, but it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
You'll need to recode the callers to use INSERT ... ON DUPLICATE KEY UPDATE, or something equivalent, to accomplish this.
Related
Let me put it in simplest words possible - is it possible to delete the row, which actually set On the trigger i.e. I have an AFTER INSERT ON <table2> trigger, the SQL in the trigger INSERT / UPDATE another <table1> (based on a WHERE), and finally tends to delete the entry/row in the (the row which basically fired the trigger).
Trigger SQL:
DELIMITER ||
DROP TRIGGER IF EXISTS trg_adddata_tmp ||
CREATE TRIGGER trg_adddata_tmp
AFTER INSERT ON adddata_tmp
FOR EACH ROW
BEGIN
IF EXISTS (SELECT * FROM adddata WHERE data_id = new.data_id AND account_name = new.account_name) THEN
UPDATE adddata SET data_id = new.data_id, account_name = new.account_name, user_name = new.user_name, first_name = new.first_name, last_name = new.last_name WHERE data_id = new.data_id AND account_name = new.account_name;
ELSE
INSERT INTO adddata (data_id, account_name, user_name, first_name, last_name)
VALUES(new.data_id, new.account_name, new.user_name, new.first_name, new.last_name);
END IF;
DELETE FROM adddata_tmp WHERE id = new.id;
END;
||
Without the DELETE (just above the END;) the trigger works fine - UPDATE if exist otherwise INSERT - with DELETE statement gives the following error:
Error Code: 1442
Can't update table 'adddata_tmp' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
By the way, the error is pretty self-explanatory, but still wanted to make sure if this is possible - if not this way, may be some other way around i.e. I want the adddata_tmp table to be empty (or clean-ed up) all the time (on INSERT copies the data to main adddata table)
One idea, I have in mind is, to use an EVENT to clean-up the adddata_tmp based on some status field - which gets set as the last statement in the trigger (in place of DELETE).
No, you can't do this with trigger, here's what the documentation says:
A stored function or trigger cannot modify a table that is already
being used (for reading or writing) by the statement that invoked the
function or trigger.
If adddata_tmp table needs to be empty all the time then I would not write trigger at all. Instead, I would recommend moving adddata update logic in the script/service that tries to insert the data into adddata_tmp.
update
If we are doing bulk inserts and the data (in adddata_tmp table) is not utilised anywhere else then we can write a cron job to clean up the table (i.e. the one that executes let's say every 10 minutes). Also, TRUNCATE would be more efficient (than DELETE) in this case.
USE test;
CREATE TRIGGER AvgUpdateTrigger AFTER INSERT ON test.score
FOR EACH ROW
BEGIN
INSERT INTO test.average (test.average.TestID, test.average.TestAvg)
(SELECT test.score.TestID, avg(test.score.ScoreValue) FROM test.score GROUP BY test.score.TestID)
ON DUPLICATE KEY
UPDATE test.average.TestAvg = (SELECT avg(test.score.ScoreValue) FROM test.score WHERE test.score.TestID = test.average.TestID GROUP BY test.score.TestID);
END;
im trying to update one table(average) when another one gets changed(score)
it is telling me to add a semicolon but as you can see there is one there allready
If a trigger (or any stored procedure) contains only one statement, you don't need BEGIN and END:
CREATE TRIGGER AvgUpdateTrigger AFTER INSERT ON test.score
FOR EACH ROW
INSERT INTO test.average (TestID, TestAvg)
SELECT test.score.TestID, avg(test.score.ScoreValue)
FROM test.score
GROUP BY test.score.TestID
ON DUPLICATE KEY UPDATE
test.average.TestAvg = VALUES(TestAvg);
I also replaced the subquery with VALUES(TestAvg), since this value has already been selected.
Using mysql 5.6. I have two tables. One has a whitelist of hashes. When I insert a new row into the other table, I want to first compare the hash in the insert statement to the whitelist. If it's in the whitelist, I don't want to do the insert (less data to plow through later). The inserts are generated from another program and are text files with sql statements.
I've been playing with triggers, and almost have it working:
CREATE TRIGGER `Filelist` BEFORE INSERT ON `filelist`
FOR EACH ROW BEGIN IF(
SELECT count( md5hash ) FROM whitelist WHERE md5hash = new.hash ) >0
THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Can not have duplicates';
END IF ;
END
But there's a problem. The Signal throwing up the error stops the import. I want to skip that line, not stop the whole import.
Some searching didn't find any way to silently skip the import.
My next idea was to create a duplicate table definition, and redirect the insert to that dup table. But the old and new don't seem to apply to table names.
Other then adding an ignore column to my table then doing a mass drop based on that column after the import, is there any way to achieve my goal? I'm having problems with this too [Ignore is a tinyint(1)]:
DELIMITER $$
CREATE TRIGGER whitelisted
BEFORE INSERT ON filelist
FOR EACH ROW BEGIN
IF (select count(md5hash) from whitelist where md5hash=new.hash) > 0 THEN
SET Ignore = true;
END IF;
END$$
/* This is now "END$$" not "END;" */
/* Reset the delimiter back to ";" */
DELIMITER ;
#1064 - You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near ') THEN SET Ignore = true;
END IF; END' at line 4
Any suggestions? I've also tried
SET Ignore = 1;
SET Ignore = '1';
SET new.Ignore = {all of the above};
I'm not sure if I follow this specification:
I have two tables. One has a whitelist of hashes. When I insert a new row into the other table, I want to first compare the hash in the insert statement to the whitelist. If it's in the whitelist, I don't want to do the insert
My first attempt would be like this:
INSERT INTO filelist (filename, hash)
SELECT "myfile", "ABCD" FROM DUAL
WHERE NOT EXISTS(
SELECT md5hash FROM whitelist where md5hash = "ABCD"
);
I don't think you need triggers for this at all unless there are missing details in your requirements.
I take it you're doing some kind of ON INSERT-trigger.
You need to add the following statement to your trigger to make it work as wanted:
FOR EACH ROW
This will make the trigger execute once on every row.
I have the following three (InnoDB-) tables in a MySQL database:
Entity (DLID)
Category (CatID, CatName)
hasCategory (DLID, CatID)
Now, upon insertion into the table hasCategory I would like to make sure, that each Entity is associated with at least one Category. Thus, I wrote the following trigger:
delimiter |
create trigger Max before insert on hasCategory for each row begin
if (exists (select distinct DLID from Entity where not exists (select distinct new.DLID from new))) then
signal sqlstate '45000'
set message_text = 'Min of 1 category per entity required';
end if;
end|
delimiter ;
Now, when I execute the following query: insert into hasCategory values (1, 1); I get the error error code 1146: table mydb.new does not exist. I have created some other triggers similar to this one, also referring to the new-table, where it worked perfectly well. Yet, I don't get it, what causes the error in this particular trigger.
Is it possible that the select statement causes some trouble? I've read that only select into statements are valid in procedures, but I don't know if this has got anything to do with this.
Thanks for your help!
select distinct new.DLID from new
there is no table new in your DB just as the error states. You can use NEW for the record that will be inserted in your trigger but you cannot use it as a table name and select from it.
try
if (select 1 from Entity where DLID = new.DLID) = 1 then
insert into creditcard_info (member_id,card_type,card_number)
values ('1','Discover','555')
where not exists (
select * from creditcard_info
where card_number='555' and
card_type='Discover')
I want to be able to check if a card number already exists..
If card_number exists and card card_type exists then don't add
else insert this new card number along with card type
I am having difficultly with inserting into a table where a certain number does not exists.
Im getting this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near 'where not exists (select * from
creditcard_info where card_number='555')' at line 2
Thank you all in advance for helping me :)
It looks like you're trying to perform an INSERT ... SELECT statement.
However, adding a unique index in both fields should be more efficient.
You need to create a multi-column unique index. The code is as below:
ALTER TABLE creditcard_info ADD UNIQUE idx_card_number_card_type(card_number,card_type);
This should run as a separate query. And you need to add it once.
The other possible option is to add before insert trigger if the condition is more complicated than a simple unique check.
Here is the create trigger syntax:
Create Trigger card_type_unique_card_number_exists Before Insert on creditcard_info
FOR EACH ROW BEGIN
DECLARE it_exists INT;
Set it_exists=(select count(*) from creditcard_info where card_number='555' and card_type='Discover');
If it_exists>0 Then
#Throw a meaningful exception by let's say inserting into a table which doesn't exist or something
END IF;
END