I currently have two tables for which I have listed the codes below:
CREATE TABLE `class` (
`id` int(11) NOT NULL,
`class_no` int(11) NOT NULL,
`class_title` varchar(11) NOT NULL,
`no_of_students` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `enrolment` (
`id` int(11) NOT NULL,
`ssn` varchar(11) NOT NULL,
`class_no` int(11) NOT NULL,
`grade` varchar(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I currently have the following statement, which when you enter something into 'Enrolment', and the class number you type in already matches a class_no in the table 'Class', then it adds whatever is typed into grade to no_of_students. What I now need it to do is if someone say typed into enrollment (2, 4, 6, 8) and the class_no 6 didn't already exist in the 'Class' table, it would add into 'Class' with the class_no as 6 and the no_of_students as 8.
DELIMITER $
CREATE TRIGGER `after_insert_add_one`
AFTER INSERT ON `enrolment`
FOR EACH ROW UPDATE class
SET class.no_of_students = class.no_of_students + NEW.grade
WHERE class_no = NEW.class_no
$
DELIMITER ;
(When you add an enrolment row do you really want to increment class.no_of_students by the value of grade? Seems like you might want to increment it by one. I wrote my answer assuming that.)
(I suspect you didn't show, in your question, the indexes definitions for your tables. I suspect you didn't show how your id columns get set. Presumably they are set with autoincrement. If that's not true my answer is probably worthless.)
MySQL offers an INSERT ... ON DUPLICATE KEY UPDATE statement. You can change your trigger to use it, something like this (not debugged).
DELIMITER $
CREATE TRIGGER `after_insert_add_one`
AFTER INSERT ON `enrolment`
FOR EACH ROW
INSERT INTO class
(class_no, no_of_students, grade)
VALUES (NEW.class_no, 1, NEW.grade)
ON DUPLICATE KEY
UPDATE SET class.no_of_students = class.no_of_students + 1$
DELIMITER ;
For this to work correctly you need a unique index on class.class_no. You can create it as follows:
CREATE UNIQUE INDEX class_no ON class (class_no);
By the way, you need some sort of index on class.class_no. Without it neither your original trigger nor the new one will perform very well. And, your "business rules" seem to require each value of class_no to have just one row in the class table. So you may as well use a unique index.
Pro tip: Giving your columns accurate and descriptive names is almost always worth a lot of trouble early in your project. If, for example, the column grade actually is a count of new students, you'll create years of confusion. The more successful your project is, the more confusion you'll create.
This can be done in app logic or with a trigger, the later below:
CREATE TRIGGER after_insert_add_one AFTER INSERT ON enrolment FOR EACH ROW
BEGIN
DECLARE counter int DEFAULT -1;
SELECT COUNT() INTO counter
FROM class
WHERE class_no = NEW.class_no;
IF counter = 0 THEN
# no classes exist with enrolment ID
INSERT INTO class (class_no) VALUES (NEW.class_no);
ELSE:
# class exists ++
UPDATE class
SET class.no_of_students = class.no_of_students + NEW.grade
WHERE class_no = NEW.class_no;
END IF;
END;
Related
Following up to see if there is a way, know this might be simple for you guys:
I need to create a table with 5 columns where columns(CostPrice) and columns(SellPrice) need to add a value into columns(Difference) in MySQL. In the example let's say I have items I wish to load and upon selling them I want that Difference calculated in the database not through a view because I'd like to reference that "Difference" value in another table when I'll at a later stage be doing a view.
What I'm trying to achieve:
itemAdd/itemName/costPrice/sellPrice/difference
2019-08-22/Table/100/150/50
CREATE TABLE Results (
itemAdd Timestamp,
itemName varchar(255) NOT NULL,
costPrice int(11) NOT NULL,
sellPrice int(11) NOT NULL,
(costPrice - sellPrice) as 'difference'
)
Reason why I want to do this through table create is because I'd update the costPrice and sellPrice of the items and would like to keep track of how the difference changed, but at the same time I'd like to reference the difference column from another table so that value shouldn't stay statically the same. Hope this makes sense. . .
If you set up insert/update triggers, you can determine the difference any time there is a change.
(live sandbox example: https://www.db-fiddle.com/f/8DVeXFdsrEBwHg168GZU2o/22)
Update your table to define the difference column.
CREATE TABLE Results (
itemAdd Timestamp,
itemName varchar(255) NOT NULL,
costPrice int(11) NOT NULL,
sellPrice int(11) NOT NULL,
difference int(11) NOT NULL
);
Then define triggers to handle the insert/updates:
-- handle inserts
DELIMITER $$
CREATE TRIGGER trg_insert_price_diff
BEFORE INSERT ON Results
FOR EACH ROW
BEGIN
SET NEW.difference = NEW.sellPrice - NEW.costPrice;
END$$
DELIMITER ;
-- handle updates
DELIMITER $$
CREATE TRIGGER trg_update_price_diff
BEFORE UPDATE ON Results
FOR EACH ROW
BEGIN
SET NEW.difference = NEW.sellPrice - NEW.costPrice;
END$$
DELIMITER ;
I have two tables: config(last_inserted_id) and element(id) is there any chance to get the last inserted id any time when new rows are created in element table and execute a update in column last_inserted_id at config table?
I have wrote this:
CREATE TRIGGER UPDATE_CONFIG_VALUES AFTER INSERT ON element
BEGIN
UPDATE config SET last_inserted_id = last_insert_id();
END;
END;
Is that right? What happen if I delete a row in element table? Should the value get updated in config table or not" How I avoid this?
config table
CREATE TABLE IF NOT EXISTS `cmplatform`.`isrl_config` (
`id` INT NOT NULL AUTO_INCREMENT,
`logo_address` VARCHAR(250) NOT NULL,
`name` VARCHAR(250) NOT NULL,
`rif` VARCHAR(20) NOT NULL,
`address` TEXT NOT NULL,
`phone` VARCHAR(14) NOT NULL,
`last_retention_number` INT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
TEST this ( Not tested)
CREATE TRIGGER element_inserted_tg AFTER INSERT ON element
FOR EACH ROW
BEGIN
DECLARE count INT;
SELECT COUNT(1) INTO count FROM config;
IF count == 1
UPDATE config SET last_inserted_id = NEW.id;
ELSE
INSERT INTO config VALUES (NEW.id);
END IF;
END;
CREATE TRIGGER element_deleted_tg AFTER DELETE ON element
FOR EACH ROW
BEGIN
UPDATE config SET last_inserted_id = (SELECT MAX(id) FROM element);
END;
Trigger is traditional way to do this requirement but not unique way. Another way is process it in your data access code. Let say that you have a DAO method to create new Element, you can get the id of element created and update it into last_inserted_id. If you do this way, you have to makesure there is ONLY ONE THREAD calling insert element method at a time.
I have the following table.
CREATE TABLE people(
first_name VARCHAR(128) NOT NULL,
nick_name VARCHAR(128) NULL
)
I would like to prevent people from having their nickname be the same as their firstname if they attempt that insertion. I do not want to create an index on either of the columns just a rule to prevent the insertion of records where the first_name and nick_name are the same.
Is there a way to create a rule to prevent insertion of records where the first_name would equal the nick_name?
CREATE TRIGGER `nicknameCheck` BEFORE INSERT ON `people` FOR EACH ROW begin
IF (new.first_name = new.nick_name) THEN
SET new.nick_name = null;
END IF;
END
Or you can set first_name to NULL which will cause SQL error and you can handle it and show some warning.
You only need triggers for BEFORE INSERT and BEFORE UPDATE. Let these check the values and abort the operation, if they are equal.
Caveat: On older but still widely used versions of MySQL (before 5.5 IIRC) you need to do something bad, such as read from the written table or easier read from an inexistant table/column (in order to abort).
AFTER INSERT trigger to test and remove if same ...
CREATE TABLE ek_test (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
one INT NOT NULL,
two INT NOT NULL
);
delimiter //
CREATE TRIGGER ek_test_one_two_differ AFTER INSERT ON ek_test
FOR EACH ROW
BEGIN
IF (new.one = new.two) THEN
DELETE FROM ek_test WHERE id = new.id;
END IF;
END//
delimiter ;
INSERT INTO ek_test (one, two) VALUES (1, 1);
SELECT * FROM ek_test;
NOTE you will also need AFTER UPDATE trigger.
I'm new to mysql triggers and I'm trying to figure it out how should a trigger be created for the following case.
I have a table with the following structure:
CREATE TABLE `trigger` (
`group` int(3) NOT NULL,
`order` int(3) NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`group`,`order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is how the table would look with some sample data:
The trigger that I want to create should make sure that, for each new record added with a given group, the order field is updated with the correct order index.
So, if I were to add a new record with the group 1, the order field will be automatically be updated to the next order which, for the given example would be 4.
The following statements inside a trigger should do the trick.
DECLARE neworder INTEGER;
SELECT max(`order`) + 1 INTO neworder FROM `trigger` WHERE `group` = NEW.`group`;
SET NEW.`order` = neworder;
BTW, it's not a great idea to use reserved words for table or column names.
You might want to reconsider your naming scheme.
We are in the process of migrating between 2 systems and need to have 2 fields for one of our database tables that always stay in sync. Here is the table structure:
CREATE TABLE `example` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`object_id` int(11) NOT NULL DEFAULT '0',
`value` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `object_id` (`object_id`)
);
Every time one of the systems inserts a new row we need to have object_id set to id. We can't use 'before insert' since the id column is an auto_increment column so it's value is NULL before insert and due to the limitations of the MySQL 'after insert' on triggers I can't do the following:
CREATE TRIGGER insert_example
AFTER INSERT ON example
FOR EACH ROW
SET NEW.object_id = NEW.id;
I can't update the code for either system so I need a way to accomplish this on the database side. Both systems are going to be inserting new rows. How can I accomplish this?
Using a trigger which fires before the insert should do the job
CREATE TRIGGER insert_example
BEFORE INSERT ON example
FOR EACH ROW
SET NEW.object_id = NEW.id;
EDIT:
As the OP pointed out NEW.id won't work with auto-increment; one could use the following trigger (use at own risk):
CREATE TRIGGER insert_example
BEFORE INSERT ON example
FOR EACH ROW
SET NEW.object_id = (
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'example'
);
But I'd rather re-think this somewhat strange requirement - why do you need the pk value twice in the table?
Is there any reason you cant use a BEFORE INSERT trigger?
I've always seen AFTER INSERT triggers as a method to manipulate other tables rather than the table for which the trigger was executed on.
Rule of thumb, manipulate table the trigger is running on = BEFORE INSERT, manipulate other tables AFTER INSERT :)
I think your trigger will never create in the first place because you can't refer NEW.column_name in an AFTER INSERT trigger.
Try doing this in a BEFORE INSERT trigger (PLEASE IGNORE THIS FIX AS IT WILL NOT WORK):
CREATE TRIGGER `insert_example` BEFORE INSERT ON `t`
FOR EACH ROW
SET NEW.`object_id` = NEW.`id`;
Please change the table and column names as per your schema.
Hope this helps.