I've got a problem with a trigger in MySQL.
My table is the following :
CREATE TABLE IF NOT EXISTS Possessioncartes (
id_carte SMALLINT UNSIGNED,
PRIMARY KEY (id_carte, pseudonyme),
CONSTRAINT fk_inv_carte_id_possession FOREIGN KEY (id_carte) REFERENCES Cartes(id_carte) on delete cascade on update cascade,
pseudonyme VARCHAR(40),
CONSTRAINT fk_inv_carte_pseudo_possession FOREIGN KEY (pseudonyme) REFERENCES Joueurs(pseudonyme) on delete cascade on update cascade,
date_possession DATETIME NOT NULL,
methode_possession VARCHAR(20),
date_non_possession DATETIME,
etat SMALLINT UNSIGNED DEFAULT 1 NOT NULL
);
and my trigger :
create trigger posseder after insert on Possessioncartes
for each row begin
set #date_non_possession = new.date_possession
where #id_carte = new.id_carte;
end$$
( When I add a new card to the table, the trigger should update all the rows that has the same ID )
when I tried to add a new row, I got no errors but no row was updated.
I tried omitting the # but I got an "unknown system variable" error.
Thanks for your time.
Triggers cannot modify the table they are "ON", nor any table involved in the query that triggered them.
For example an update trigger on A, cannot modify B for an update statement like UPDATE A INNER JOIN B ON something SET A.x = somethingelse....
I have a table called 'estoque' with a foreign key that references another table called 'produto'. Then I've populated both tables with a few rows.
Here are my tables:
CREATE TABLE `produto` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NOME` varchar(45) NOT NULL,
`PRECO` float NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `NOME_UNIQUE` (`NOME`)
);
CREATE TABLE `estoque` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`ID_PRODUTO` int(11) NOT NULL,
`QUANTIDADE_PRODUTO` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `fk_Estoque_Produto1_idx` (`ID_PRODUTO`),
CONSTRAINT `fk_Estoque_Produto1` FOREIGN KEY (`ID_PRODUTO`)
REFERENCES `produto` (`ID`)
);
I need 'estoque' to always reference all existing rows on 'product'. So I'e created an AFTER INSERT and an AFTER UPDATE triggers on product:
CREATE TRIGGER `cadastrar_novo_produto_no_estoque`
AFTER INSERT ON `produto`
FOR EACH ROW
INSERT IGNORE INTO estoque (ID_PRODUTO)
VALUES (NEW.ID);
EDIT: Actually, since I can't alter the 'ID' column on 'produto' because it is a primary key, I've think I don't need the AFTER UPDATE trigger at all. Am I right?
CREATE TRIGGER `atualizar_novo_produto_no_estoque`
AFTER UPDATE ON `produto`
FOR EACH ROW
UPDATE estoque
SET estoque.ID_PRODUTO = NEW.ID
WHERE OLD.estoque.ID_PRODUTO = OLD.ID;
Now I need a trigger so that every time I delete a row from 'product', it also deletes the corresponding row in 'estoque'.
I've tried creating one like this:
CREATE TRIGGER `deletar_produto_inexistente_no_estoque`
BEFORE DELETE ON `produto`
FOR EACH ROW DELETE FROM estoque
WHERE estoque.ID_PRODUTO = ID;
But whenever I try to delete a row from 'produto' I get the following error:
ERROR 1175: 1175: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
SQL Statement:
DELETE FROM `papelaria`.`produto` WHERE (`ID` = '6')
So I've tried it with the OLD keyword, as such:
CREATE TRIGGER `deletar_produto_inexistente_no_estoque`
BEFORE DELETE ON `produto`
FOR EACH ROW DELETE FROM estoque
WHERE OLD.estoque.ID_PRODUTO = OLD.ID;
And then I get this error instead:
ERROR 1054: 1054: Unknown column 'OLD.estoque.ID_PRODUTO' in 'where clause'
SQL Statement:
DELETE FROM `papelaria`.`produto` WHERE (`ID` = '6')
What am I missing or doing wrong?
P.S.: Not sure if it's worth mentioning but I'm fairly new to sql and programming in general, so I'd appreciate it if you took it into consideration when answering (for all purposes, just assume I don't know anything about anything ^^)
Thank you in advance!
You can modify your FK to:
CONSTRAINT `fk_Estoque_Produto1`
FOREIGN KEY (`ID_PRODUTO`)
REFERENCES `produto` (`ID`)
ON DELETE CASCADE
Then you will not need the before delete trigger any longer as records in estoque table will be deleted automatically.
Similar, adding ON UPDATE CASCADE will solve your 'update issue' in case someone update record's PK.
Still not sure why you'd like to have the dummy records in the estoque table.
I have read through countless threads on this and am still missing something.
When I delete a row from either table no constraint or cascade occurs.
My goal is to cascade delete any child rows.
CREATE SCHEMA IF NOT EXISTS `my_schema`
DEFAULT CHARACTER SET latin1;
USE `my_schema`;
SET foreign_key_checks = 0;
DROP TABLE IF EXISTS `test_types`;
DROP TABLE IF EXISTS `test_core_types`;
SET foreign_key_checks = 1;
-- -----------------------------------------------------
-- Table `test_core_types`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `test_core_types` (
`test_core_type_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`data` VARCHAR(100) NOT NULL,
PRIMARY KEY (`test_core_type_id`))
ENGINE = InnoDB
AUTO_INCREMENT = 1;
CREATE UNIQUE INDEX `test_core_types__data_UNIQUE` ON `test_core_types` (`data` ASC);
-- -----------------------------------------------------
-- Table `test_types`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `test_types` (
`test_type_id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
`test_core_type_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(45) NOT NULL,
`is_viewable` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`test_type_id`))
ENGINE = InnoDB
AUTO_INCREMENT = 1;
CREATE UNIQUE INDEX `test_types__name_UNIQUE` ON `test_types` (`name` ASC);
CREATE INDEX `idx_test_core_type_00` ON `test_types` (`test_core_type_id` ASC);
ALTER TABLE `test_types`
ADD CONSTRAINT `fk_test_core_type_00`
FOREIGN KEY (`test_core_type_id`)
REFERENCES `test_core_types` (`test_core_type_id`)
ON DELETE CASCADE
ON UPDATE NO ACTION;
Insert:
INSERT INTO `test_core_types` (`test_core_type_id`, `data`) VALUES ( 1, 'General');
INSERT INTO `test_types` (`test_type_id`, `test_core_type_id`, `name`, `is_viewable`) VALUES ( 1, 1, 'My General Item', 1);
Delete:
DELETE FROM `test_core_types` WHERE `test_core_type_id` = 1;
Result:
SELECT * FROM `test_core_types`;
/* --> Row Deleted */
SELECT * FROM `test_types`;
/* --> Row still exists */
When I perform a delete the row is deleted without errors.
Does not matter which table.
Any help is greatly appreciated.
Theory:
For your child table (test_types) you have mentioned ON DELETE CASCADE; which means when you delete a row from parent table (test_core_types); same delete will get cascaded to child table (S) as well and corresponding related row from child table will be deleted.
After your delete query; if you try a select from both table you will find 0 rows present. That's the actual behavior of ON DELETE CASCADE.
For Real example check the below mentioned fiddle link
http://sqlfiddle.com/#!2/33014e/1
You've specified a DELETE rule of CASCADE.
We'd expect a delete from the parent table would succeed, related rows in the table with the foreign key reference will also be deleted. We wouldn't expect any error.
If you want the DELETE operation in your code to throw an error, then define the foreign key reference with a DELETE rule of RESTRICT.
I recommend you verify that FOREIGN_KEY_CHECKS is enabled, and that the foreign key constraint is actually defined (i.e. that the ALTER TABLE statement that added the constraint succeeded. I've never tried specifying NO ACTION as an update rule; I know that's the default when no rule is specified, but I always specify either RESTRICT, CASCADE or SET NULL.) Also verify that the table is actually using the InnoDB storage engine.
SHOW VARIABLES LIKE '%foreign_key_checks%' ;
SHOW CREATE TABLE `test_types` ;
I would like to create a trigger for my table table_master.
The table schema of table_master is simple:
master_id INT(11) AUTO_INCREMENT, PRIMARY, NOT NULL
title VARCHAR(50) NOT NULL
And here is another relation table rel_master_another_tbl
master_id INT(11) PRIMARY, NOT NULL
another_id INT(11) PRIMARY, NOT NULL
What I want to achieve is, when a DELETE query is issued on table_master, the trigger will check whether the master_id is used in rel_master_another_tbl . UPDATE: If yes, rollback / cancel the DELETE query.
How can I achieve this?
CREATE TRIGGER check_before_delete BEFORE DELETE ON table_master
// what should I put here?
END;
The behavior you are trying to implement already exists in the database and can be utilized via an ON DELETE RESTRICT trigger. An example of defining your tables to take advantage of this is shown below:
CREATE TABLE `master` (
`master_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) DEFAULT NULL,
PRIMARY KEY (`master_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `rel_master_another_tbl` (
`master_id` int(11) NOT NULL,
`another_id` int(11) NOT NULL,
KEY `i_master_id` (`master_id`),
FOREIGN KEY `fk_rel_master_another_tbl_master` (`master_id`)
REFERENCES `master` (`id`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
RESTRICT in this context means that attempts to delete rows from your master table will fail, if there are corresponding rows in your rel_master_another_tbl that are referring to masters id column. Also, do note that RESTRICT is the default option for both ON DELETE and ON UPDATE triggers for foreign keys, so you could actually define your foreign key as shown below and it would still function the same:
FOREIGN KEY `fk_rel_master_another_tbl_master` (`master_id`)
REFERENCES `master` (`id`)
Refer to the MySQL documentation on foreign key constraints for more information.
If you want to check if this id exists in another table then you can do that this way:
DELIMITER $$
CREATE TRIGGER check_before_delete BEFORE DELETE ON table_master
FOR EACH ROW
BEGIN
DECLARE has_row TINYINT;
SELECT 1
INTO has_row
FROM rel_master_another_tbl
WHERE master_id = OLD.master_id;
IF has_row IS NOT NULL THEN
// PUT YOUR CODE HERE
END IF;
END$$
However check Perception's comment about setting key constrain between tables and using ON DELETE RESTRICT trigger as this could be proper solution for your problem.
This was originally going to be an "update" on the logical schema presented in another question here: Getting ERROR 1701, ERROR 1452 and ERROR 1305 errors in MySQL - Need some expertise...
I think I have successfully verified this schema to 1st and 2nd Normal Form, but am unsure if this meets 3rd Normal Form. Here is the model in question:
And here is the associated code (note: for some reason I cannot recreate 1:1 relationships in the sql code as illustrated in the logical model above):
-- database_schema.sql.
-- This sql script creates the structure.
-- of the rugby club database.
DROP DATABASE IF EXISTS database_rugby;
CREATE DATABASE database_rugby;
USE database_rugby;
-- Create the "person" table.
--
-- This table has one:one relationships
-- with the parent, coach and player
-- tables.
DROP TABLE IF EXISTS `person` ;
CREATE TABLE `person` (
`personID` INT(5) NOT NULL AUTO_INCREMENT ,
`firstName` VARCHAR(50) NOT NULL ,
`lastName` VARCHAR(50) NOT NULL ,
`dateOfBirth` DATE NOT NULL ,
`streetAddress` VARCHAR(150) NOT NULL ,
`suburbAddress` VARCHAR(150) NULL DEFAULT NULL ,
`cityAddress` VARCHAR(150) NOT NULL ,
`photo` BLOB NULL DEFAULT NULL ,
PRIMARY KEY (`personID`))
ENGINE = InnoDB;
-- Create the "parent" table.
DROP TABLE IF EXISTS `parent` ;
CREATE TABLE `parent` (
`parentID` INT(5) NOT NULL ,
`personID` INT(5) NOT NULL ,
PRIMARY KEY (`parentID`, `personID`),
FOREIGN KEY (`personID`) REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "school" table.
DROP TABLE IF EXISTS `school` ;
CREATE TABLE `school` (
`schoolID` INT(5) NOT NULL AUTO_INCREMENT ,
`schoolName` VARCHAR(100) NOT NULL ,
PRIMARY KEY (`schoolID`))
ENGINE = InnoDB;
-- Create the "player" table.
--
-- Inherits fields from the "person"
-- and "school" tables.
DROP TABLE IF EXISTS `player` ;
CREATE TABLE `player` (
`playerID` INT(5) NOT NULL ,
`personID` INT(5) NOT NULL ,
`schoolID` INT(5) NOT NULL ,
PRIMARY KEY (`playerID`, `personID`),
FOREIGN KEY (`personID`)
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`schoolID`)
REFERENCES `school` (`schoolID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "coach" table.
DROP TABLE IF EXISTS `coach`;
CREATE TABLE `coach`(
`coachID` INT(5) NOT NULL ,
`dateBeganCoaching` DATE NOT NULL ,
`personID` INT(5) NOT NULL ,
PRIMARY KEY (`coachID`, `personID`),
FOREIGN KEY (`personID`)
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "family" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "parent"
-- and "player" tables.
DROP TABLE IF EXISTS `family` ;
CREATE TABLE `family` (
`parentID` INT(5) NOT NULL ,
`playerID` INT(5) NOT NULL ,
FOREIGN KEY (`playerID` )
REFERENCES `player` (`playerID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`parentID`)
REFERENCES `parent` (`parentID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- Create the "grade" table.
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade`(
`gradeID` INT(5) NOT NULL AUTO_INCREMENT ,
`gradeName` VARCHAR(50) NOT NULL ,
`minWeight` INT(3) NOT NULL ,
`maxWeight` INT(3) NOT NULL ,
`minAge` INT(3) NOT NULL ,
`maxAge` INT(3) NOT NULL ,
`ballSize` INT(1) NOT NULL ,
PRIMARY KEY (`gradeID`) )
ENGINE = InnoDB;
-- Create the "coachQualification" table.
DROP TABLE IF EXISTS `coachQualification` ;
CREATE TABLE `coachQualification` (
`qualID` INT(5) NOT NULL AUTO_INCREMENT ,
`qualName` CHAR(5) NOT NULL ,
`gradeID` INT(5) NOT NULL ,
PRIMARY KEY (`qualID`) ,
FOREIGN KEY (`gradeID`)
REFERENCES `grade` (`gradeID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "homePhone" table.
DROP TABLE IF EXISTS `homePhone` ;
CREATE TABLE `homePhone` (
`homePhoneID` INT(5) NOT NULL AUTO_INCREMENT ,
`homeNumber` CHAR(9) NOT NULL ,
PRIMARY KEY (`homePhoneID`))
ENGINE = InnoDB;
-- Create the "mobilePhone" table.
DROP TABLE IF EXISTS `mobilePhone` ;
CREATE TABLE `mobilePhone` (
`mobilePhoneID` INT(5) NOT NULL AUTO_INCREMENT ,
`mobileNumber` CHAR(10) NULL DEFAULT NULL ,
PRIMARY KEY (`mobilePhoneID`))
ENGINE = InnoDB;
-- Create the "emailAddress" table.
DROP TABLE IF EXISTS `emailAddress` ;
CREATE TABLE `emailAddress` (
`emailAddressID` INT(5) NOT NULL AUTO_INCREMENT ,
`emailAddress` CHAR(10) NULL DEFAULT NULL ,
PRIMARY KEY (`emailAddressID`))
ENGINE = InnoDB;
-- Create the "Contact" table
--
-- This is a linking table
-- that describes the many:many
-- relationships between "person"
-- and the "homePhone", "mobilePhone",
-- and "emailAddress" tables.
DROP TABLE IF EXISTS `contact` ;
CREATE TABLE `contact` (
`personID` INT(5) NOT NULL ,
`homePhoneID` INT(5) NOT NULL ,
`mobilePhoneID` INT(5) NULL DEFAULT NULL ,
`emailAddressID` INT(5) NULL DEFAULT NULL ,
FOREIGN KEY (`personID` )
REFERENCES `person` (`personID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`homePhoneID`)
REFERENCES `homePhone` (`homePhoneID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`mobilePhoneID`)
REFERENCES `mobilePhone` (`mobilePhoneID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`emailAddressID`)
REFERENCES `emailAddress` (`emailAddressID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "qualificationSet" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "coach"
-- and "coachQualification" tables.
DROP TABLE IF EXISTS `qualificationSet` ;
CREATE TABLE `qualificationSet` (
`coachID` INT(5) NOT NULL ,
`qualID` INT(5) NOT NULL ,
FOREIGN KEY (`coachID`)
REFERENCES `coach` (`coachID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`qualID`)
REFERENCES `coachQualification` (`qualID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "team" table.
DROP TABLE IF EXISTS `team` ;
CREATE TABLE `team` (
`teamID` INT(5) NOT NULL AUTO_INCREMENT ,
`teamName` VARCHAR(50) NOT NULL ,
`teamYear` INT(2) NOT NULL ,
`gradeID` INT(5) NOT NULL ,
PRIMARY KEY (`teamID`) ,
FOREIGN KEY (`gradeID`)
REFERENCES `grade` (`gradeID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "teamAllocation" table
--
-- this is a linking table for a
-- many:many relationship between
-- team and player tables.
DROP TABLE IF EXISTS `teamAllocation` ;
CREATE TABLE `teamAllocation` (
`teamID` INT(5) NOT NULL ,
`playerID` INT(5) NOT NULL ,
FOREIGN KEY (`teamID` )
REFERENCES `team` (`teamID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`playerID`)
REFERENCES `player` (`playerID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
-- Create the "teamCoachAllocation" table.
--
-- This is a linking table
-- that describes the many:many
-- relationship between "coach"
-- and "team" tables.
DROP TABLE IF EXISTS `teamCoachAllocation` ;
CREATE TABLE `teamCoachAllocation` (
`coachID` INT(5) NOT NULL ,
`teamID` INT(5) NOT NULL ,
FOREIGN KEY (`coachID`)
REFERENCES `coach` (`coachID`)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (`teamID`)
REFERENCES `team` (`teamID`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
From these links below:
http://en.wikipedia.org/wiki/First_normal_form
http://en.wikipedia.org/wiki/Second_normal_form
http://en.wikipedia.org/wiki/Third_normal_form
This is my understanding of Normalisation to 3NF:
First normal form means to not allow repeating values
Second normal form means 1NF and attributes are dependant on whole primary key and not part of a primary key (I think of this as partitioning tables if values in that table need to relate to eachother in some way and have comparisons made).
Third normal form means 2NF and no transistive values (e.g if x = y and y = z, x = z)
Putting that knowledge from theory into practice is quite hard for me, especially translating that "practise" into working, normalised MySQL code. If someone is able to help me go through the model and give me some pointers about normalising the model to 3NF, I would appreciate it very much.
Thanks in advance!
I think this isn't in 3NF, around the contact table. If I'm wrong this is still a bad way of storing the data and should probably be changed.
Sorry if this is a little confused...
It is entirely possible to have the following structure in your contact table as the entire table is the primary key:
+----------+-------------+---------------+---------+
| personid | homephoneid | mobilephoneid | emailid |
+----------+-------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 2 |
| 1 | 1 | 2 | 3 |
+----------+-------------+---------------+---------+
As you can see both homephoneid and mobilephoneid are duplicated so updating the table homephone will result 3 updates to contact.
I disagree with the data-model as you require a person to have a homehone I don't have one, only a mobile. In this situation, when creating a new person you have to also create a new contact and a new homephone.
As contact is just a primary key and a primary key value cannot be null, you also require the creation of a mobilephone and an emailaddress, which means that person is dependent on emailaddress.
As emailaddress is dependent on contact, which in turn is dependent on person you've created a circular dependency, which breaks 3NF.
As I see it you have a two options if you want to ensure that people have to have a home phone number:
If you only want a person to have one homephone then add this
into the person table. It's unique contact level information and
should be stored there.
If you want to enable people to have multiple home phone numbers -
remembering that multiple people can use the same phone number - but
don't care about mobiles then you need to create a table
personhomephones, say, with the primary key personid,
homephoneid and not put homephoneid in the contact table.
Personally I wouldn't do either of these. I wouldn't ensure that someone has to have a home phone number but instead a primary phone number, where you don't care what type it is. I would allow people to add different methods of contact but allow these not to exist
This would require the following structure:
person - add primaryPhoneID
primaryphone ( primaryphoneID, phonenumber) - PK primaryphoneID
Then for the contact methods that are allowed to not exist:
contactType ( contactTypeID, contactType ) - PK contactTypeID
contact ( contactID, contactTypeID, value ) - PK contactID, contactTypeID
personContact ( personID, contactID, contactTypeID ) - PK everything
Whilst this may result in duplication between contact and primaryphone they are distinct bits of data and I think this is fine. If you're insistent on not allowing any duplication at all you'd have to separate out the phones from the other methods of contact, which makes the model more complicated:
phonetype ( phoneTypeId, phoneType )
phone ( phoneID, phoneTypeID, phonenumber) - PK phoneID, phoneTypeID
contactPhone ( personID, phoneTypeID, phoneID ) - PK everything
There is an algorithm to eventually decompose each relation in your schema in order to get an equivalent schema in 3NF. Google is good for that!!
To get tips about your schema design you should at least describe the context and the functional constraints about the entities you need to represent.