I'm trying to create a trigger which will capture any event that will occur when I update any column in the table before and after updating, let's say I have 4 columns:
first_name address city country
Let's say I edited first_name lets say Jack to Henk.
It should insert in another table the command (i.e. update) ,time , description but inside the description I want it to write Jack was changed to John by current user(i.e using the current-user () function),if it is a city being updated from Mechinkova to Tostov, it should do the same do with other columns.
I know I want to have to add the concat function inside the trigger, I want it to be like this for example:
DROP TRIGGER IF EXISTS adminpanel.soft//
CREATE TRIGGER adminpanel.soft BEFORE UPDATE ON adminpanel.aggrement
FOR EACH ROW
BEGIN
INSERT INTO adminpanel.aggretrigger(cmd, time, cmd_user, last_name, city) VALUES("INSERT", NOW(), CURRENT_USER(), new.last_name, new.city);
END
//
What you are asking for is an audit trigger. It is very easy to implement.
Let us first slightly modify your main table. Let's add a field id of integer datatype as the primary key to the table, so your table would look like:
tablename
( id integer PK
, first_name varchar
, address varchar
, city varchar
, country varchar
)
Now, you will need a table, say UNIVERSAL_AUDIT_ENTRY table that will store the changes made to the data in your schema.
From what experience I have, I suggest you create this table as follows:
universal_audit_entry
( universal_audit_entryid integer PK
, table_name varchar -- captures the name of the table
, column_name varchar -- captures the name of the column
, entry_type varchar -- captures the event, e.g., 'INSERT' or 'UPDATE'
, primary_key_value integer -- captures, e.g., the value in tblename.id
, from_str varchar -- captures the value that was present before
, to_str varchar -- captures the value that was changed into
, timestamp datetime -- captures the timestamp of the event
, username varchar -- captures the name of user
)
Now with the universal_audit_entry table ready, your trigger should look somewhat like:
CREATE TRIGGER adminpanel.soft
BEFORE UPDATE ON adminpanel.aggrement
FOR EACH ROW
BEGIN
IF UPDATING(first_name) THEN
INSERT INTO universal_audit_entry VALUES
( 123 -- example for universal_audit_entryid
, 'TABLENAME'
, 'FIRST_NAME'
, 'UPDATE'
, new.id
, old.first_name
, new.first_name
, current_timestamp()
, current_user);
END IF;
END;
//
You can use similar logic to audit more columns in the same table and other tables also.
Note:
This code is not tested. I have added it here only for illustration purposes. This code for trigger is not supposed to be used directly.
new and old are the pseudo-records that are generated during an update statement. These records correspond to the rows that are being updated. :new means the row after the update statement runs and :old means the row before the update statement runs. This works in Oracle. Kindly make sure if it works in MySQL also.
EDIT
You can read more about MySQL triggers here. Read more about audit trail here and this SO question.
Related
I have 2 tables with different structures.
CREATE TABLE test1
(
id INTEGER PRIMARY KEY,
EmpName VARCHAR(50),
Empid INTEGER
);
CREATE TABLE test2
(
Empid INTEGER PRIMARY KEY,
EmpFName VARCHAR(50),
EmpLName VARCHAR(50)
);
Is there a way to insert rows from test2 table into test1? If the row exists in test1 it should update the row as well. I think it's possible with Merge statement but it's not available for MySQL. Is there a similar function like this in MySQL?
I've looked into INSERT ... ON DUPLICATE KEY UPDATE but the tables should have the same primary keys.
I think this can help you.
Create Trigger to detect when insert/update data in your table test2.
Inside Trigger use REPLACE INTO to change data in your table test1.
Please check this link for additional of REPLACE INTO command.
Is there a way to insert rows from test2 table into test1? If the row exists in test1 it should update the row as well
UPDATE test1
JOIN test2 USING (Empid)
SET test1.EmpName = CONCAT_WS(' ', EmpFName, EmpLName)
Pay attention - EmpName max length is 50 whereas total length of combined name may be up to 50+1+50=101, so the combined value may be truncated. Increase max length for EmpName.
If you need to perform this operation automatically when the data in test2 is inserted/updated then use AFTER INSERT and AFTER UPDATE triggers, like
CREATE TRIGGER tr
AFTER INSERT -- and the same trigger on AFTER UPDATE event
ON test2
FOR EACH ROW
UPDATE test1
SET EmpName = CONCAT_WS(' ', NEW.EmpFName, NEW.EmpLName)
WHERE test1.Empid = NEW.Empid;
I have a database table in mysql
create table userstable
(
id int not null auto_increment,
name varchar(80) not null,
username varchar(80) not null,
primary key(id)
);
How to add new row in mysql database, so that username will be 'name'+('id'*100)
Example :
ID name username
1 A A100
2 B B200
3 C C300
4 user user400
You need trigger for that process. Create the following trigger
CREATE TRIGGER username_change
BEFORE INSERT ON userstable
FOR EACH ROW
BEGIN
SET NEW.username = CONCAT(NEW.name,(NEW.id*100));
END
OR
INSERT INTO userstable (id,name, username) VALUES (2, 'B', CONCAT(name,(id*100)));
Try this.
You'll need to write a trigger or update the field after insertion. A similar question provides more insight:
Can you access the auto increment value in MySQL within one statement?
As #ArunKrish correctly pointed out, you may use TRIGGER to update the data as part of the insert. Another option is to use view:
CREATE VIEW v1 AS
SELECT id,name,CONCAT(name,id*100) AS username FROM userstable;
You may also use the query as-is, without view:
SELECT id,name,CONCAT(name,id*100) AS username FROM userstable;
I need to create in MySQL trigger on such schema:
mail
oid id
varchar name
varchar reference
adress_mail
oid id
oid id_mail
oid id_adress
adress
oid id
varchar name
after something is inserted into adress_mail it is updating 'mail.reference' with value like every 'adress.name' for example:
I am inserting adress_mail with (1,5,6) and (1,5,7) so trigger will update 'mail.reference' with values from 'adress.name where adress.id = 6' and 'adress.name where adress.id = 7'
Q: The whole problem is how to loop on adress_mail table and get all
'adress.name' in 1 varchar and then just update 'mail.reference' with
that value?
I can setup something like var (variable) in trigger and then collect all results from select?
PS 'mail.reference' it's varchar row to improve some searching feature of application, because I don't have possibility to loop on 'adress_mail' table.
Just don't do that ! You are using an sql data base, and the main idea of it is table relations, so when you'll have to look for data from address linked to mail, perform a select with joins on address_mail.
how can i create a trigger function before adding/updating,the function should check records that have the same id (i.e comparison by id with existing objects that have the same property as the temporary_object)If a record with the id is found, then that entry is set to the time_dead, and then it adds an entry containing the corresponding values of the attributes found in that record (except those that are set for a new record), when time_dead is empty then time_create of a new time is equal to that time at the current moment . Thus,a new record time_create is like the time_dead's ancestor.
If a record with that id is found then it is added to the database with the establishment as the time_create of the current time.
for example here is a simple explanation(just for explanation purposes)
id time_create time-dead student amount
1 06.12 07.12 henry 500
1 07.12 henry 1000
so if a student called henry with id 1 entered a room at 06.12 and left at 07.12 the next time he enters another room again time_dead will be equal to time_create(so time_dead of old entry and time_create of new entry - will be equal)
these are my tables below in sql format
CREATE TABLE temporary_object
(
id integer NOT NULL,
time_create timestamp without time zone NOT NULL,
time_dead timestamp without time zone,
CONSTRAINT temporary_object_pkey PRIMARY KEY (id, time_create)
)
CREATE TABLE persons
(
fname text,
fsurname text,
)
INHERITS (temporary_object)
CREATE TABLE rooms
(
roomnum integer,
course integer,
passport text,
students_number text
)
INHERITS (temporary_object)
this is what i am trying to do but im afraid i do not know how to finish it but im 100% not right may some help out
CREATE TRIGGER trigger2
BEFORE INSERT OR UPDATE
ON persons
FOR EACH ROW
EXECUTE PROCEDURE func1();
and this is the function
CREATE OR REPLACE FUNCTION func1() RETURNS TRIGGER AS $persons$
DECLARE
time_create integer;
time_dead timestamp;
id timestamp;
BEGIN
IF (TG_OP = 'INSERT') THEN
time_create=
I can't tell you what I'm missing from your question, but I try to answer what I think I understood.
Row level triggers can access the version of the row affected with the NEW and OLD variables (depending on TG_OP). In this case, you can use NEW:
CREATE OR REPLACE FUNCTION func1()
RETURNS TRIGGER AS
$persons$
DECLARE
i integer;
BEGIN
IF TG_OP = 'INSERT'
THEN
UPDATE persons
SET time_dead = NEW.time_create
WHERE
id = NEW.id -- we are looking for the same ID
AND time_dead IS NULL
;
ELSE -- UPDATE
-- do here something
END IF;
END;
$persons$
LANGUAGE plpgsql;
This is only a starter, modify it to your needs.
My idea was to have a table called "changelog_table" that had the following columns:
updated_table //the table being updated
updated_column //the column being updated
updated_row //the id of the row being updated
updated_content //this is what they updated the field to
updated_user //the user who updated
updated_datetime //the timestamp it was updated
I think this is both the minimum and maximum of what I'd really want, but I may be wrong.
Also...I do not understand, after weeks of reading, how to store variables (like "which table is being updated" and "which column is being updated" and so forth) in my trigger.
So let's say I had a table called "foo_table", with a column "bar_column", with a row "58008", that is being updated to "this is the new content", by user "peter_griffin", at 12/30/2013 at noon.
What would a trigger that could capture that look like?
You'll need to create separate triggers on each table for UPDATE (and, if so desired, for INSERT and DELETE too). They could each call the same stored procedure that does the actual logging.
The trigger can pass to the stored procedure a parameter containing the name of the table on which the operation is being performed (since the trigger is table-specific, it will know this - it'll have to be hardcoded); to detect which column(s) have been updated you'll need to compare, within each trigger, NEW.column with OLD.column for each column in the respective table.
For example:
CREATE TRIGGER upd_tbl_name AFTER UPDATE ON tbl_name FOR EACH ROW
CALL AuditLog('UPDATE', 'tbl_name', NEW.id, CONCAT_WS(',',
IF(NEW.columnA <=> OLD.columnA, NULL, CONCAT('columnA:=', NEW.columnA)),
IF(NEW.columnB <=> OLD.columnB, NULL, CONCAT('columnB:=', NEW.columnB)),
-- etc.
));
CREATE PROCEDURE AuditLog(
Action VARCHAR(10),
TableName VARCHAR(64),
RowID INT,
Columns TEXT,
)
INSERT INTO changelog_table VALUES (
Action,
TableName,
RowID,
Columns
USER(),
NOW(),
);