Trigger with update - mysql

when I update the data in a table Form in the tables Book from the number of colbook must be subtracted -1.
please help to do this with a trigger
table Form
Create table Form (
idForm int not null primary key auto_increment,
date_of_issue date not null,
return_date date ,
idBook int not null,
Foreign key(idBook) references Book (idBook));
table Book
Create table Book (
idBook int not null primary key auto_increment,
name varchar(45) not null,
colBook int(11) null;
Filling a table Form
Insert into Form (idForm, date_of_issue)
Values(1, "2018-11-11");
Filling a table Book
Insert into Book (idBook, name, colBook)
Values(1, Garri Potter, 5);
table update request Form
update Form
set return_date = "2000-03-03"
where idBook = 1;

You just need to create a trigger on table "Form" as below:
delimiter $$
CREATE TRIGGER form_trigger_1
AFTER INSERT ON form FOR EACH ROW
BEGIN
update book
set colbook = colbook - 1
where idbook = old.idbook;
END
delimiter ;

Related

MYSQL: Write a trigger to record the message "A new row is inserted" and the time of insertion in a separate table when inserting a new row into table

I have the following table:
CREATE TABLE Employees (
EmployeeID INT,
LastName varchar(20) NOT NULL,
FirstName varchar(20) NOT NULL,
Birthdate date
);
I need to write a trigger to record the message "A new row is inserted", and the time of insertion into a new separate table called Employees_audit when inserting a new row into the Employees table.
I am stumped with this and have looked at example triggers to help me but I cannot quite figure out what to do. Any help is very much appreciated.
Reference and here
Consider the following tables:
CREATE TABLE Employees (
EmployeeID INT,
LastName varchar(20) NOT NULL,
FirstName varchar(20) NOT NULL,
Birthdate date
);
create table Employees_audit (
note varchar(255),
inserted_record_dt datetime,
EmployeeID int
);
The trigger you need:
create trigger Insert_Employees_audit after insert on Employees
for each row
begin
insert into Employees_audit (EmployeeID,note, inserted_record_dt) values (new.EmployeeID,'A new row is inserted', now());
end
Some data example
insert into Employees values (1,'Test','Test','2000-01-01');
Result of:
select *
from Employees_audit;
note inserted_record_dt EmployeeID
A new row is inserted 2022-11-21 10:01:34 1
https://dbfiddle.uk/KGa4ditu

After Creating after update trigger i cant update any

DROP TABLE IF EXISTS Sales;
CREATE TABLE Sales (
id INT AUTO_INCREMENT,
product VARCHAR(100) NOT NULL,
quantity INT NOT NULL DEFAULT 0,
fiscalYear SMALLINT NOT NULL,
fiscalMonth TINYINT NOT NULL,
CHECK(fiscalMonth >= 1 AND fiscalMonth <= 12),
CHECK(fiscalYear BETWEEN 2000 and 2050),
CHECK (quantity >=0),
UNIQUE(product, fiscalYear, fiscalMonth),
PRIMARY KEY(id)
);
DROP TABLE IF EXISTS log;
CREATE TABLE log (
id INT AUTO_INCREMENT PRIMARY KEY,
timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
text VARCHAR(100)
);
Triggers
CREATE DEFINER=`root`#`localhost` TRIGGER `sales_AFTER_UPDATE` AFTER UPDATE ON `sales`
FOR EACH ROW
BEGIN
INSERT INTO log VALUES(NOW(),CONCAT('Update Student Record ', OLD.quantity));
END
UPDATE test for.sales SET quantity = 36
WHERE (id = 1);
ERROR 1136: 1136: Column count doesn't match value count at row 1
Iam new in mySQL Please help
You should specify columns in INSERT statement in your trigger explicitly, as you do not set all values in a row (auto incremented column excluded).
So it would be
INSERT INTO log(timestamp, text) VALUES (NOW(),CONCAT('Update Student Record ', OLD.quantity));
You have some errors.
First based on your trigger you need another column on log table which is as following
quantity INT NOT NULL DEFAULT 0
Second , do not use Keywords and Reserved Words like text and timestamp, it is a bad practice. If you do please put it inside backticks
Third your insert statement should be
INSERT INTO log(`timestamp`,`text`,quantity) VALUES(NOW(),'Update Student Record', OLD.quantity);
there is no need for CONCAT.
Fourth,
`sales`
table is not the same as Sales table, because you have used backticks.
Full working trigger below:
DELIMITER //
CREATE TRIGGER `sales_AFTER_UPDATE` AFTER UPDATE ON Sales
FOR EACH ROW
BEGIN
INSERT INTO log(`timestamp`,`text`,quantity) VALUES(NOW(),'Update Student Record', OLD.quantity);
END//
DELIMITER ;
Check working demo:
https://www.db-fiddle.com/f/iqwShcHK3AGJvU4MDbxDku/0

MySQL trigger to target an attribute of a column

I am working with an overlap super/subtype relationship dealing with person(s) in my DB. What I would like to do is have the overlapping subtypes insert new rows when the supertype gains a new row. I have attached my LRD to clarify the relationship. LRD
I would like to create a trigger that inserts new person rows into the correct subtype based on the attributes employee/user in the person table.
The code I have attempted so far gives me an error upon inserting rows into person noting "employee column does not exist". I would assume this is because this code is trying to use the if statement for the subtypes where it is in fact absent.
I would appreciate any feedback.
Table Details
CREATE TABLE PERSON
(person_id int(10) not null AUTO_INCREMENT,
first_name varchar(15) not null,
last_name varchar(15) not null,
employee char(1),
participant char(1),
CONSTRAINT person_pk PRIMARY KEY (person_id))
ENGINE=InnoDB;
CREATE TABLE EMPLOYEE
(eperson_id int(10) not null AUTO_INCREMENT,
enterprise_email varchar(30),
manager_id int(10),
CONSTRAINT employee_pk PRIMARY KEY (eperson_id),
CONSTRAINT employee_fk1 FOREIGN KEY(eperson_id) REFERENCES PERSON(person_id) ON update cascade,
CONSTRAINT employee_fk2 FOREIGN KEY(manager_id) REFERENCES EMPLOYEE(eperson_id) ON update cascade)
ENGINE=InnoDB;
CREATE TABLE PARTICIPANT
(pperson_id int(10) not null AUTO_INCREMENT,
city varchar(30),
state varchar(2),
zip int(5),
sign_up_date date,
termination_date date,
CONSTRAINT participant_pk PRIMARY KEY (pperson_id),
CONSTRAINT participant_fk FOREIGN KEY(pperson_id) REFERENCES PERSON(person_id) ON update cascade)
ENGINE=InnoDB;
Trigger Code
DELIMITER //
CREATE TRIGGER subtype_creator
AFTER INSERT ON PERSON
FOR EACH ROW
BEGIN
IF (employee = ā€˜eā€™ ) THEN
INSERT INTO EMPLOYEE
SET eperson_id = NEW.person_id,
last_name = NEW.last_name,
enterprise_email = NULL,
manager_id = NULL;
IF (participant = ā€˜pā€™ )THEN
INSERT INTO PARTICIPANT
SET pperson_id = NEW.person_id,
city=NULL,
state = NULL,
zip = NULL,
sign_up_date =NULL,
termination_date = NULL;
END IF;
END IF;
END//
DELIMITER ;
This may work for you.
First off, I think to have the AUTO_INCREMENT attribute on columns EMPLOYEE.eperson_id and PARTICIPANT.pperson_id is not needed.
Since both of those columns are FOREIGN KEYS and are referencing back to the person_id column of table PERSON, they need to have, and will be getting, their values from that column through the TRIGGER anyway so no need to autoincrement them in the tables.
So I would change that.
This TRIGGER should work with populating both tables EMPLOYEE and PARTICIPANT after INSERT on table PERSON:
DELIMITER //
CREATE TRIGGER subtype_creator
AFTER INSERT ON PERSON
FOR EACH ROW
BEGIN
INSERT INTO EMPLOYEE(eperson_id, enterprise_email, manager_id)
VALUES(NEW.person_id, NULL, NULL);
INSERT INTO PARTICIPANT(pperson_id, city, state, zip, sign_up_date, termination_date)
VALUES(NEW.person_id, NULL, NULL, NULL, NULL, NULL);
END//
DELIMITER ;
Hope this helps you.
I ended up figuring out two methods to solve my issue. I ended up altering my 'employee' and 'participant' into boolean/tinyint data types.
CREATE TABLE PERSON
(person_id int(10) not null AUTO_INCREMENT,
first_name varchar(15) not null,
last_name varchar(15) not null,
employee tinyint(1),
participant tinyint(1),
CONSTRAINT person_pk PRIMARY KEY (person_id))
ENGINE=InnoDB;
After that alteration I decided to try and break up the one trigger into two. This was successful.
Type 1
DELIMITER //
CREATE TRIGGER employee_creator
AFTER INSERT ON PERSON
FOR EACH ROW
BEGIN
IF (NEW.employee = 1 ) THEN
INSERT INTO EMPLOYEE
SET eperson_id = NEW.person_id,
last_name = NEW.last_name,
enterprise_email = NULL,
manager_id = NULL;
END IF;
END//
DELIMITER ;
DELIMITER //
CREATE TRIGGER participant_creator
AFTER INSERT ON PERSON
FOR EACH ROW
BEGIN
IF (NEW.participant =0 )THEN
INSERT INTO PARTICIPANT
SET pperson_id = NEW.person_id,
city=NULL,
state = NULL,
zip = NULL,
sign_up_date =NULL,
termination_date = NULL;
END IF;
END//
DELIMITER ;
After inplementing that first option I realized the ELSEIF would allow me to not split the two and create a single trigger.
Type 2
DELIMITER //
CREATE TRIGGER employee_creator
AFTER INSERT ON PERSON
FOR EACH ROW
BEGIN
IF (NEW.employee = 1 ) THEN
INSERT INTO EMPLOYEE
SET eperson_id = NEW.person_id,
last_name = NEW.last_name,
enterprise_email = NULL,
manager_id = NULL;
ELSEIF (NEW.participant =0 )THEN
INSERT INTO PARTICIPANT
SET pperson_id = NEW.person_id,
city=NULL,
state = NULL,
zip = NULL,
sign_up_date =NULL,
termination_date = NULL;
END IF;
END//
DELIMITER ;

Update row in first table and insert a row into a second table in a single query

I'm trying to figure it out how to insert a row into a table on updating a particular field in the second table.
Let's say I have table 1 (dif):
CREATE TABLE dif
(
Position INT(10) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) UNSIGNED DEFAULT 0 NOT NULL
);
ALTER TABLE dif
ADD CONSTRAINT dif_article_pKey_fk
FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;
and table 2 (article):
CREATE TABLE IF NOT EXISTS article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
Number SMALLINT NOT NULL DEFAULT 0
PRIMARY KEY (pKey)
);
The table article is populated with some data and should be only updated. Table "dif" is empty at the beginning. So, let's say I'm updating the fields on "article" like this:
UPDATE article SET pKey = 15, Name = SomeName, Number = 22 WHERE pKey=15;
Can I somehow combine the UPDATE query with this?
INSERT INTO dif (pKey, Number) VALUES (15, 12);
The "12" is the difference between the "article.Number" before and after UPDATE.
No, but you can make a stored procedure that does both of those things and then execute it in a single statement.
create procedure GiveThisABetterName
(
in pKey int,
in newNumber int,
in currentNumber int,
in newName varchar(100)
)
begin
update
article
set
Name = newName, Number = newNumber
where
pKey = pKey;
insert into dif (pKey, Number) values (pKey, newNumber);
end
My mysql syntax is rusty, but that should be close. Then when you want to execute it:
call GiveThisABetterName(12, 15, 22, 'Some Name');
EDIT: After reading your question again, it seems to me that you're trying to make your data model track audit information that it's just not set up to accommodate naturally. Do you have control over the model? If so, consider something like this (see here for a working example of what's below):
CREATE TABLE IF NOT EXISTS article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
PRIMARY KEY (pKey)
);
CREATE TABLE ArticleNumbers
(
Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
Difference SMALLINT(3)
);
ALTER TABLE ArticleNumbers
ADD CONSTRAINT ArticleNumbers_article_pKey_fk
FOREIGN KEY (pKey) REFERENCES article (pKey) ON UPDATE CASCADE;
Maybe add a few views to make things easier:
CREATE VIEW GroupedArticleNumbers
as
select pKey, max(Counter) as Counter
from ArticleNumbers
group by pKey;
CREATE VIEW CurrentArticles
as
select article.pKey, article.Name, numbers.Number, numbers.Difference
from article
left outer join GroupedArticleNumbers filter on article.pKey = filter.pKey
left outer join ArticleNumbers numbers on filter.Counter = numbers.Counter;
Since you can track the number separately from the base record now but still easily determine what the current number is, you can now combine your update and insert statement functionality. See below.
First, some test data:
insert into article (Name) values ('Test');
insert into ArticleNumbers (pKey, Number, Difference) values (1, 10, null);
insert into ArticleNumbers (pKey, Number, Difference) select 1, 20, 20 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 50, 50 - Number from CurrentArticles where pKey = 1;
insert into ArticleNumbers (pKey, Number, Difference) select 1, 15, 15 - Number from CurrentArticles where pKey = 1;
See how nicely that works out once the overhead of setting up the schema has been done?
To get the current number for the article we created:
select * from currentarticles where pKey = 1
To get the number history for that article:
select * from article
left outer join articlenumbers on article.pkey = articlenumbers.pkey
order by counter asc
If you're willing to mess with your data model, you can have an alternative to stored procedures.
Alternatively, if you want to use triggers as #Jonathan Leffler suggested, something like this should work:
CREATE TABLE article (
pKey smallint(3) unsigned NOT NULL AUTO_INCREMENT,
Name varchar(80) COLLATE utf8_roman_ci NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
PRIMARY KEY (pKey)
);
CREATE TABLE ArticleNumbers
(
Counter int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
pKey SMALLINT(3) UNSIGNED NOT NULL,
Number SMALLINT(3) DEFAULT 0 NOT NULL,
Difference SMALLINT(3)
);
delimiter $
create trigger tr_u_article
before update on article
for each row
begin
insert into ArticleNumbers (pKey, Number, Difference) select old.pKey, new.Number, new.Number - old.Number
end;
delimiter ;

Reserve/Assign a new row in another table with each row added in one

I'll like to find out if it's possible to do the following:
after insertion of data into table a, a row will be created automatically in table b and the Note_Id (its primary key) will be stored in one of the attributes (which is a foreign key that references to the primary key in table b) in table a.
CREATE TABLE table_a ( D_Id int(5) NOT NULL AUTO_INCREMENT,
User_Id int(8) not null,
Note_Id int(5) not null, -- this is the foreign key that points to table b
PRIMARY KEY (D_Id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE table_b ( Note_Id int(5) NOT NULL AUTO_INCREMENT,
Note_Description varchar(50) null,
PRIMARY KEY (Note_Id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Thanks!
delimiter $$
CREATE TRIGGER ins_Document
AFTER INSERT ON TABLE_A FOR EACH ROW
BEGIN
set #notenum=(Select max(Note_Id) from TABLE_B);
if(#notenum=0) then begin new.Note_Id=1;
end;
else
new.Note_Id=#notenum+1;
end if;
INSERT INTO TABLE_B (Note_Id) VALUES (NEW.Note_Id);
END$$
delimiter ;
Have a look into triggers: Create Trigger
Here you can react on events like inserts into a table and define respective actions for that.