Problem is this: I have to write the data to a physical file each time after a certain table is updated.
Normally I would do this with a trigger, for example:
CREATE TRIGGER log_to_file AFTER INSERT ON LOG
BEGIN
...
END
How do I refer to the data that triggers a database trigger in the first place from within the trigger code ? This is namely the data I have to analyze and have to write to a file.
Not sure what you want. As per my understanding , you want to refer a row that is just inserted. You can refer that with NEW in code. So this might work for you.
CREATE TABLE LOG
(
ID INT(11) NOT NULL,
Description NVARCHAR(50) NULL,
)
CREATE TRIGGER log_to_file AFTER INSERT ON LOG
FOR EACH ROW
BEGIN
/* Logic can be put here for each inserted row */
INSERT INTO any_table (ID,Description,Date) VALUES(New.ID,New.Description,SYSDATE())
END
Related
At a high level I am already aware that you can not insert a new row to the same table and that one should consider a SPROC. Here is the use case though. There is a 3rd party web app and this MySQL DB that I have, so I have no control over the application flow. A request has come in to simplify data entry. What I do have control over is the database. The app is like a CRM and has a contacts table and there is a 2nd contact_relationships table where I am putting the trigger on. Basically the contact_relationships needs three fields. Two contactIDs (INT) from the contact table and a relationship_type varchar(45) like (Spouse, Sibling, External Family and so on).
The goal here is when a new row is added (the TRIGGER) to the contact_relationships table, that we ALSO write a 2nd row to the SAME TABLE that inverts the contactIDs and keeps the relationship_type. This ensures there is also a record relationship established for the other contact from the same single entry. (ideally should be done in the app).
I'm at my whits end over what should be a stupid simple operation. I even tried this creative implementation.
I created a new _temp table
CREATE TABLE `_temp` (
`id_temp` int(11) NOT NULL AUTO_INCREMENT,
`Contact_id` int(11) DEFAULT NULL,
`Relation_id` int(11) DEFAULT NULL,
`Relationship_Type` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id_temp`)
I have two triggers on the contact_relationships table
#1
CREATE DEFINER=`root`#`localhost` TRIGGER `contact_relationships_BEFORE_INSERT` BEFORE INSERT ON `contact_relationships` FOR EACH ROW BEGIN
insert into _temp (Contact_id,Relation_id,Relationship_Type)
values(NEW.Contact_id,NEW.Relation_id,NEW.Relationship_Type);
END
#2
CREATE DEFINER=`root`#`localhost` TRIGGER `contact_relationships_AFTER_INSERT` AFTER INSERT ON `contact_relationships` FOR EACH ROW BEGIN
delete from _temp;
END
On the _temp table I have this trigger
CREATE DEFINER=`root`#`localhost` TRIGGER `_temp_AFTER_DELETE` AFTER DELETE ON `_temp` FOR EACH ROW BEGIN
#DO Sleep(2);
# Sleep commented out as it did not work and only delayed the error
insert into contact_relationships (Relation_id,Contact_id,Relationship_Type) values(OLD.Contact_id,OLD.Relation_id,OLD.Relationship_Type);
END
So my thinking here in pseudo code is like this
When a row is inserted into the contact_relationships table write the inverted row to a temp table as I can not write it to the **same table from inside the trigger**.
AFTER the triggered inserted row is complete lets delete the row in the temp table so we can create a DELETE trigger on that other table to write the desired row into the contact_relationship.
At this stage I believe the TRIGGER and TRANSACTIONS on the contact_relationships table are DONE
On the temp Table a trigger and transaction firing AFTER any contact_relationships transactions
Results are maddening and always the same albeit internal or external. I have tried creative functions and sprocs all with the same aggravating results.
Contact Relationships : Add New
Can't update table 'contact_relationships' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Query:
insert into `Contact_Relationships` set `Contact_id`='2', `Relation_id`='3', `Relationship_Type`='Extended Family'
I'm completely brain dead on how I may accomplish this - anyone have a way to pull this off?
dsoden.
What I would do is:
Inside the trigger definition, you can get the "inserted_id" of the relationship that was inserted ( You can get it withLAST_INSERT_ID() ).
Once you have it, you can SELECT from that record into temp variables:
SELECT `Contact_id`,`Relation_id`,`Relationship_Type` INTO #cont_id, #rel_id, #rel_type
FROM contact_relationships
WHERE id = LAST_INSERT_ID()
And then do the Insert of the new relationship in the reverse order, with the same relationship type:
INSERT INTO contact_relationships (`Contact_id`,`Relation_id`,`Relationship_Type`) VALUES ( #rel_id, #cont_id, #rel_type);
If that's what you're aiming for..
Something like:
When a relationship between Anne and John as Siblings is inserted,
insert the John,Anne,Siblings relationship as well
Hi I want to create trigger if it's condition satisfy then it's body should be executed and I want to display some message or any data that should be displayed if trigger body executed.
I want that if quantity of product went less then 50 then it should display message or some data.
Is it possible to display message ?
Here testdata is table name.
Code :
delimiter //
create trigger trigger2 before update on test.testdata
for each row
begin
if new.qty < 50 then
**display here some message that quantity is less**
end if;
end;
//
delimiter ;
You cannot do it, there is no place to output them in MySQL. As a work around you can add your message to the table, and then read this table.
Short example -
CREATE TABLE table1 (
column1 VARCHAR(255) DEFAULT NULL
);
CREATE TABLE messages (
id INT(11) NOT NULL AUTO_INCREMENT,
message VARCHAR(255) DEFAULT NULL,
time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DELIMITER $$
CREATE TRIGGER trigger1
AFTER INSERT
ON table1
FOR EACH ROW
BEGIN
INSERT INTO messages(message) VALUES ('new action');
END
$$
DELIMITER ;
Also, you could use UDF function write your logic.
More information - CREATE FUNCTION Syntax for User-Defined Functions.
For Quick and plain answering: You cannot Display Messages From Triggers. You may Only Throw errors.
You are propably not knowing the reason u use triggers in databases assuming from your question. We all have passed that level so dont worry. U have understood the syntax when we use triggers but not how and what they can do and not.
A trigger will do (for your case BEFORE an UPDATE) something concerning the database and only that.
That means the trigger cannot display any message on your screen. You can only handle database staff and not all of the actions are allowed for that too or some actions arent even recommended!.
That is for the theory part.
To give you a solution to your problem now.
The only thing you can do to know when the trigger has worked (that means when the new.qua<50) or basically check anything with any other trigger is the following. (Just a small fast solution):
You need to create a Table that will handle all logging of the
triggers.
Add in it an ID field, a descr field that will hold the action of
the triggerex. BefUpdate, BefInsert etc. another field for the
propably the condition that triggered the logging and antyhing else
u want displayed later in the application.
Then inside the if condition u are using write and insert
statemement to fill the info in the new (logging) table.
in your app later select that logging table to see the messages.
That is a useful and fast way to log, not only triggers but also functions (stored procs).
Judt for reference i give you s sample code with the CREATE, and the INSERT statement for your trigger.
CREATE TABLE LOGGER (
ID BIGINT PRIMARY KEY AUTO_INCREMENT,
DESCR_ACTIVITY VARCHAR(10),
ACTIVITY VARCHAR(50),
DT TIMESTAMP,
CONDITIONVALUE VARCHAR(50)
)
In the IF of your code now make it as :
if new.qty < 50 then
INSERT INTO LOGGER VALUES ('BEFINS','CHECKING QUA',NULL,'QUANTITY IS LOWER THAN 50')
end if;
And even from the workbench or from your application u can just :
SELECT * FROM LOGGER
to see the loggings.
But if i am confused from the reading and you want just to throw an error u can read the Mysql Documentation concerning throwing errors:
enter link description here
What u can do is in your if condition write something like:
if new.qty < 50 then
SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT = 'Lower than 50', MYSQL_ERRNO = 1000;
endif;
What u should always NOT DO is alter the same table that a trigger is assigned and use only small portion of not so complex code in the trigger.
Hope i helped a bit.
Also, you can display any message using the select command.
IF (NEW.qty < 50) THEN
SELECT "message that quantity is less" AS Output;
END IF
Place above code inside the trigger. It will print the output
What I'm trying to achieve is, I want to automate the values of the table between the users and folders table. Since it's a many-to-many relationship I created the user_folders table. Currently the server (nodejs) gets the request with userid, clientfolderid and some an array of bookmarks (which are not important now). It checks if the user already has this folder, by selecting from the user_folders table and if it's not existing it inserts a new row into the folder table. Then it has to send another statement to insert into the user_folders table.
So I have to "manually" keep the users_folder table updated.I guess this is a common problem and wanted to know if there is a pattern or a proven solution? The odd thing is that MySQL automatically handles the deletion of rows with an AFTER DELETE trigger but there is no (at least that I know of) automation with an AFTER INSERT trigger.
As I already said an AFTER INSERT trigger could possibly solve it, but I think it's not possible to pass some extra parameters to the AFTER INSERT trigger. This would be the user_id and the folder_client_id in my case.
I was thinking of a solution that I could create another table called tmp_folder which would look like:
tmp_folder
-- id
-- title
-- changed
-- user_id
-- folder_client_id
Then create an AFTER INSERT trigger on this table which inserts into folders and user_folders and then removes the row from tmp_folder again. Would this be the right way or is there a better one?
I would basically do the same with the bookmarks and user_bookmarks table. The best thing would be if it's even possible to insert a folder then the owner into the user_folders table with user_id and folder_client_id and then multiple other users into user_folders with the user_id and an default folder_client_id of -1 or something which will be updated later.
Meanwhile thanks for reading and I hope you can help me :)
PS: Is there a name for the table between 2 other tables in an m-2-m relationship?
I don't see an easy way to do this via triggers, but a stored procedure may suit you:
DELIMITER //
CREATE PROCEDURE
add_user_folder(
IN u_user_id BIGINT UNSIGNED,
IN u_folder_client_id BIGINT UNSIGNED,
IN v_title VARCHAR(255)
)
BEGIN
DECLARE u_found INT UNSIGNED DEFAULT 0;
SELECT
1 INTO u_found
FROM
user_folders
WHERE
user_id = u_user_id AND
folder_client_id = u_folder_client_id;
IF IFNULL(u_found, 0) = 0 THEN
START TRANSACTION;
INSERT INTO
folders
SET
title = v_title,
changed = UNIX_TIMESTAMP();
INSERT INTO
user_folders
SET
user_id = u_user_id,
folder_id = LAST_INSERT_ID(),
folder_client_id = u_folder_client_id;
COMMIT;
END IF;
END;
//
I'm new to working with triggers and am having a hard time understanding how to write a trigger to update a field in one table, when a record is inserted in another.
To elaborate, I have 2 tables: servTickets and servTicketNotes.
servTickets has several text fields for customer, contact, phone, email, problem description, status, etc...the PK in this table is an INT field called callID.
servTicketNotes has only 2 fields - again, the PK is an INT field 'callID' and there is a BLOB field called image which stores an image of a service report.
What I'm struggling to do is have a trigger update the status field in servTickets with a value of Closed when a new record is inserted into servTicketNotes.
I'm confused if this is an INSERT AFTER or BEFORE or BOTH scenario, but basically if a report is sent in (thereby creating a record in servTicketNotes, I want the trigger to seek out the record with the same callID in the servTickets table and change the value of status to 'Closed'.
This seems like it should be so simple, but I can't seem to grasp how to get started...
Thanks in advance for your help/guidance!
is it probably a POST trigger - which means:
AFTER you have committed the incoming record, you want to take further action - i.e. inserting into the other table.
if you do it PRE commit, then you would worry about some error happening on the Notes and you might end up with an incorrect update to the status.
You can do this with an AFTER INSERT trigger. Try something like this:
DELIMITER $$
DROP TRIGGER IF EXISTS tr_a_ins_servTicketNotes $$
CREATE TRIGGER pabeta.tr_a_ins_servTicketNotes AFTER INSERT ON servTicketNotes FOR EACH ROW BEGIN
update servTickets
set status = 'Closed'
where callID = NEW.callID;
END $$
DELIMITER ;
I need to insert a discount line into a table everything time a I insert a line into the same table.
Now i know that this could end in a endless loop but I have put checks in so it wont insert anything when the discount line is inserted.
Mysql doesnt seem to allow this.It doesnt even insert into the table let alone fire off the trigger
Any suggestions on how to do this?
You cannot alter a table (other than the current row) in a trigger attached to that table.
One solution is to insert into another table and have that trigger insert 2 rows into the table you're interested in.
If you make the other table a blackhole you don't have to worry about storage.
DELIMITER $$
CREATE TRIGGER ai_bh_test_each AFTER INSERT ON bh_test FOR EACH ROW
BEGIN
INSERT INTO table1 (field1, field2, ...) VALUES (new.field1, new.field2, ....);
INSERT INTO table1 ... values for the second row
END $$
DELIMITER ;
Why don't you just change your INSERT code into something like this? :
INSERT INTO table1 (field1, field2, ...)
VALUES ( #item, #price, ....)
, ( #item, #discount, ...) ;
Another thing would be to re-evaluate your data structure. The way it is now, it seems - from the limited information you have provided - that it's not normalized. You are storing two types of info in the table.
Perhaps you can combine the two rows (that are to be inserted every time) into one, by adding a few columns in the table.
Or by splitting the table into two tables, one for the "normal" item rows and one for the discount items.
It isn't allowed in MySQL.
One solution would be to let the trigger insert two times into another table. Then you would do writes and updates to the write table and reads from the trigger managed read table.
I needed to add an additional row to the same table, based on a specific condition on an aggregate of the table and was unable to update my application queries to handle it outside of the database, due to stability lock policy.
An alternative solution is to utilize Events in MySQL to read a "staging" table that holds the pending changes. This works by eliminating the circular reference that would be caused by the trigger. The event then executes the desired changes, without initiating the trigger, by using a session variable to leave the trigger early. Please modify the event timing to suit your needs, such as EVERY 5 SECOND.
Staging Table
CREATE TABLE `table_staging` (
`id` INT NOT NULL,
`value` VARCHAR(250) NOT NULL,
`added` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
Trigger
CREATE TRIGGER `table_after_insert` AFTER INSERT ON `table` FOR EACH ROW
tableTrigger: BEGIN
IF #EXIT_TRIGGER IS NOT NULL THEN
/* do not execute the trigger */
LEAVE tableTrigger;
END IF;
/* insert the record into staging table if it does not already exist */
INSERT IGNORE INTO `table_staging`(`id`, `value`)
VALUES (NEW.id, 'custom value');
END;
Event
CREATE EVENT `table_staging_add`
ON SCHEDULE
EVERY 1 MINUTE STARTS '2020-03-31 18:16:48'
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
/* avoid executing if the event is currently running */
IF #EXIT_TRIGGER IS NULL THEN
SET #EXIT_TRIGGER=TRUE;
/* add the values that have not already been updated */
INSERT INTO table(`value`)
SELECT
ts.value
FROM table_staging AS ts
WHERE ts.added = 0;
/* update the records to exclude them on the next pass */
UPDATE table_staging AS ts
SET ts.added = 1;
/* alternatively remove all the records from the staging table */
/* TRUNCATE table_staging; */
/* reset the state of execution */
SET #EXIT_TRIGGER=NULL;
END IF;
END;
Notes
Be sure to enable the event scheduler in your MySQL configuration (my.ini on Windows or my.cnf on Linux).
[mysqld]
event_scheduler = ON