Update table on condition from another table Trigger - mysql

I have a two tables
MovieStar (
name: char(15),
address:varchar(40),
gender:char(1),
birthdate: date,
rating:float
)
StarsIn (
movieTitle:char(25),
movieYear:int,
starname:char(15),
role:varchar(15)
)
starName is foreign key which is related to name of MovieStar.
I want to increment rating by one when Starsin record is inserted and role of the new record is 'main'
What it would do is;
on insert to starsin, check whether role = 'main'
if so, what is starname
increment rating of moviestar name = starname

I would not store the value rating in your table as it can be derived from the other table's data when it is required. And why are you using float for the count?
Create a VIEW which counts the rows in Starsin, based on your condition role = 'main' and then you have no need for the trigger and the count will always be up to date when new rows are added or removed.
With the trigger solution you also have to take account of row deletion to decrement the count.
EDIT: From the comment you made, here's a sample trigger (although the syntax may be wrong as I mainly work with SQL Server). I'm assuming the name field in the MovieStar table is a primary key and therefore unique.
CREATE TRIGGER UpdateRating AFTER INSERT ON StarsIn
FOR EACH ROW
BEGIN
UPDATE MovieStar SET rating =
(SELECT rating FROM MovieStar WHERE name = NEW.starname) + 1
FROM MovieStar INNER JOIN NEW ON MoveStar.name = NEW.starname
WHERE NEW.role = 'main'
END
I'm not familiar with MySQL, I work with SQL Server, where triggers need to be set based. I'm guessing the FOR EACH ROW part of the trigger means the statements are executed for each row inserted, but I may be wrong about that.

You need to create a trigger on insert and do the intended update.

Related

MySQL Trigger With Full-Text Search

I have a innodb table on mysql like this:
create table person (
id int not null auto_increment primary key,
name varchar(512),
birthdate date,
...
id_most_relevant int,
fulltext(name)
);
I'm want to create a trigger that, whenever a person is updated, the trigger will search other person with most relevant name (by using a full-text search) and put his id on the id_most_relevant field of the updated person, but only if this relevance is more than 95%. So, to get the percentage relevance, I devide the relevance of each person with the relevance of the new name from the person updated. Something like:
SELECT id FROM PERSON
INTO _id_most_relevant
WHERE
MATCH (name) AGAINST (_new_name) /
MATCH (new.name) AGAINST (_new_name) > 0.95
The variables _id_most_relevant and _new_name are previously declare on the trigger and the variable _id_most_relevant would be used to update the person table on id=NEW.id .
Anyone has an idea on how to do that trigger?
I'm using Mysql 5.6 and I can't update it, but I can create an auxiliary table if necessary.
CREATE TRIGGER tr_bu_person
BEFORE UPDATE
ON person
FOR EACH ROW
SET NEW.id_most_relevant = ( SELECT id
FROM person
WHERE id <> NEW.id
ORDER BY MATCH (name) AGAINST (new.name) DESC
LIMIT 1 );
But I'd avoid of FTS usage in the trigger - I'd prefer to set this column to NULL (or remove it at all) and update it to the most relevant row id value in row retrieving query (or, maybe, by event procedure).
I find out that is not possible to solve this problem using a trigger because whenever I update a person's name I will need the fulltext index already updated to get the second MATCH (on the denominator), but the fulltext index it only be updated after the tigger executes (even if it was a after update trigger).
So I have to solve this using other way, without triggers.
That said, I will close this post.

Inserting records from one table to another, but on a 'dynamic' table

Let's assume that I have a table 'A' which holds the client's orders - so it is updated within every second - and I want to copy every record of it and put it in a new table 'B'.
How would you manage to do that knowing that every moment new records are added/updated and you cant just simply 'copy + paste' it (cause in that moment new records will be added/updated) ? Do you know any way to do that ?
Please try:
CREATE TRIGGER trigger_INSERTItemDetails ON TABLEA
FOR INSERT AS
BEGIN
INSERT INTO
tableB
(
colB1,
colB2,
colB3
)
SELECT
colA1,
colA2,
colA3
FROM
INSERTED
END
and make sure that you are inserting a NOT NULL value to column Primary column of table.
Similarly you created for UPDATE and DELETE actions, so you don't need to copy separately because all actions which happen in TableA it will affect TableB also.

Issues with MySQL inserting columns below desired location

I have been having some frustration attempting to add data values to this table students. I have all the other data values and have dropped and created the column student_id. However, when trying to add the data with this query:
insert into students(student_id) values('1'),('2'),('3'),('4'),('5');
The data does not insert correctly, as it creates new columns below the first 5 which contain data.
It must be because of my not null values, but I can't not have the not null identifier.
Is there a query command that allows me to change data within already existing value-filled columns? I have been unsuccessful in finding this so far.
Here are some images to explain the problem further.
The query I have made to add my values to the table:
The data was inserted but as it is underneath the columns I need to map with a foreign key, I cannot use the column as the top 5 values are still my not null default, which is required to let me create the foreign key
Looks like you already have your records initially created without the student_id field, you want to UPDATE the current records but you're actually INSERTING new records.
You're meant to update your students with update statements such as "UPDATE students SET student_id = X where condition = Y"
Then it looks like your student_id is your primary key which you should set to AUTO_INCREMENT value.
Regards
INSERT is the wrong command since you want to update existing rows. The problem here lies within the fact that the order of the rows is nondeterministic and I think you cannot update them in one statement. One solution would be as follows:
UPDATE students SET student_id = 1 WHERE first_name = 'Berry';
UPDATE students SET student_id = 2 WHERE first_name = 'Darren';
I hope you really do have only 5 columns to update :-)

mysql create table based on columns from another table and auto updated

I could have the wording 'wrong' here (new to mysql) but i hope i've explained what I'm trying to do well.
i have a table called submissions with 4 fields submitId, studentName, submitDate, status
status refers to whether they got admitted or not.
submitId is auto incremented
Now i wanted to create another table based on that, but only if the status is true, this new table would have the submitId, studentName, submitDate, plus additional fields.
this table would have a new auto increment studentId
how would i do that so it automatically updates any new entry to the first table on the second table, but not overwrite the additional content of table 2.
i thought of using a view, but u can't add new columns on the view, right?
do i have the logic wrong here or what are the options, could someone please point me in the right direction, thanks
You want to use a trigger. See:
http://dev.mysql.com/doc/refman/5.6/en/triggers.html
You can create the trigger so that when a row is inserted into submissions with status=true, it inserts a row into your new student table. It would look something like this:
delimiter //
CREATE TRIGGER sub_ins_check AFTER INSERT ON submissions
FOR EACH ROW
BEGIN
IF NEW.status = 1 THEN
INSERT INTO your_new_table (student_name, submit_date, submit_id) VALUES (NEW.student_name, NEW.submit_date, NEW.submit_id);
END IF;
END;//
delimiter ;
Then create another trigger so that when a row is updated in submissions, it updates the row with the same submit_id in your new table, like this:
delimiter //
CREATE TRIGGER sub_ins_check AFTER UPDATE ON submissions
FOR EACH ROW
BEGIN
IF NEW.status = 1 THEN
UPDATE your_new_table SET student_name = NEW.student_name, submit_date = NEW.submit_date, (etc..)) WHERE submit_id = NEW.submit_id;
END IF;
END;//
delimiter ;
I think your data model is wrong. Remember that student my have several submissions and there may be number of students with the same name. You must distinguish them.
Is there any reason you want to duplicate student data in both tables?
If you're new to SQL, read about table normalization first.
In you Student table you should store students data and in Submission table - guess what :)
The first thing you need to do is step back and consider the problem from the perspective of logical entities.
You've identified two entities that I can see - student and submission. "Student" is an obvious entity which you may choose NOT to store in your database, but it may be better that you do. "Submission" is a more obvious one, but what is not so obvious is what a "submission" actually is. Let's assume it is some sort of transaction.
You've mentioned a "second table" without a clear indication of its role in the solution. The best I could infer is that it is meant to be some sort of historical trail on activity against a submission. If true, then I could envision a physical schema sketched out as follows:
Student table. One row per student; contains information about a student (name, id, etc.). Primary key would probably be an auto-incremented number.
Submission table. One row per submission; includes a foreign key to the student table (referencing the primary key); has its own primary key, also an auto-incremented integer. Also has triggers defined for INSERT and UPDATE. INSERT trigger causes INSERT into submission_log table; UPDATE trigger also causes INSERT into submission_log table.
Submission_log table. One row per event against the submission table. Includes all the fields of submission plus its own primary key (submission's primary key is a foreign key here), and includes an indicator field for whether it represents an insert or update on submission.
The purpose of the above is not to supply a solution, or even the framework of a solution, but rather to get you to think in terms of the logical entities you want to model in your solution, and their relationships to each other. When you have a clear picture of the logical model, it will be much easier to determine what tables are required, what their roles are, and how they will be used and how they will relate to each other.

Delayed insert due to foreign key constraints

I am trying to run a query:
INSERT
INTO `ProductState` (`ProductId`, `ChangedOn`, `State`)
SELECT t.`ProductId`, t.`ProcessedOn`, \'Activated\'
FROM `tmpImport` t
LEFT JOIN `Product` p
ON t.`ProductId` = p.`Id`
WHERE p.`Id` IS NULL
ON DUPLICATE KEY UPDATE
`ChangedOn` = VALUES(`ChangedOn`)
(I am not quite sure the query is correct, but it appears to be working), however I am running into the following issue. I am running this query before creating the entry into the 'Products' table and am getting a foreign key constraint problem due to the fact that the entry is not in the Products table yet.
My question is, is there a way to run this query, but wait until the next query (which updates the Product table) before performing the insert portion of the query above? Also to note, if the query is run after the Product entry is created it will no longer see the p.Id as being null and therefore failing so it has to be performed before the Product entry is created.
---> Edit <---
The concept I am trying to achieve is as follows:
For starters I am importing a set of data into a temp table, the Product table is a list of all products that are (or have been in the past) added through the set of data from the temp table. What I need is a separate table that provides a state change to the product as sometimes the product will become unavailable (no longer in the data set provided by the vendor).
The ProductState table is as follows:
CREATE TABLE IF NOT EXISTS `ProductState` (
`ProductId` VARCHAR(32) NOT NULL ,
`ChangedOn` DATE NOT NULL ,
`State` ENUM('Activated','Deactivated') NULL ,
PRIMARY KEY (`ProductId`, `ChangedOn`) ,
INDEX `fk_ProductState_Product` (`ProductId` ASC) ,
CONSTRAINT `fk_ProductState_Product`
FOREIGN KEY (`ProductId` )
REFERENCES `Product` (`Id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci;
The foreign key is an identifying relationship with the Product table (Product.Id)
Essentially what I am trying to accomplish is this:
1. Anytime a new product (or previously deactivated product) shows up in the vendor data set, the record is created in the ProductState table as 'Activated'.
2. Anytime a product (that is activated), does not show up in the vendor data set, the record is created as 'Deactivated' in the ProductState table.
The purpose of the ProductState table is to track activation and deactivation states of a product. Also the ProductState is a Multi-To-One relationship with the Product Table, and the state of the product will only change once daily, therefore my PKEY would be ProductId and ChangedDate.
With foreign keys, you definitely need to have the data on the Product table first, before entering the state, think about it with this logic: "How can something that dont exist have a state" ?
So pseudocode of what you should do:
Read in the vendor's product list
Compare them to the existing list in your Product table
If new ones found: 3.1 Insert it to Product table, 3.2 Insert it to ProductState table
If missing from vendor's list: 4.1 Insert it to ProductState table
All these should be done in 1 transaction. Note that you should NOT delete things from Product table, unless you really want to delete every information associated with it, ie. also delete all the "states" that you have stored.
Rather than trying to do this all in 1 query - best bet is to create a stored procedure that does the work as step-by-step above. I think it gets overly complicated (or in this case, probably impossible) to do all in 1 query.
Edit: Something like this:
CREATE PROCEDURE `some_procedure_name` ()
BEGIN
-- Breakdown the tmpImport table to 2 tables: new and removed
SELECT * INTO _temp_new_products
FROM`tmpImport` t
LEFT JOIN `Product` p
ON t.`ProductId` = p.`Id`
WHERE p.`Id` IS NULL
SELECT * INTO _temp_removed_products
FROM `Product` p
LEFT JOIN `tmpImport` t
ON t.`ProductId` = p.`Id`
WHERE t.`ProductId` IS NULL
-- For each entry in _temp_new_products:
-- 1. Insert into Product table
-- 2. Insert into ProductState table 'activated'
-- For each entry in _temp_removed_products:
-- 1. Insert into ProductState table 'deactivated'
-- drop the temporary tables
DROP TABLE _temp_new_products
DROP TABLE _temp_removed_products
END
I think you should:
start a transaction
do your insert into the Products table
do your insert into the ProductState table
commit the transaction
This will avoid any foreign key errors, but will also make sure your data is always accurate. You do not want to 'avoid' the foreign key constraint in any way, and InnoDB (which I'm sure you are using) never defers these constraints unless you turn them off completely.
Also no you cannot insert into multiple tables in one INSERT ... SELECT statement.