I'm stuck when creating my trigger in mysql (on phpmyadmin), and that's why I come to ask for your help
I have 2 tables : Assemblage and Bicyclette.
Tables Diagram:
Assemblage was built like this :
CREATE TABLE `Assemblage` (
`ID_Assemblage` int(11) NOT NULL AUTO_INCREMENT,
`Nom_Assemblage` varchar(255) NOT NULL,
`Grandeur_Assemblage` enum('Dames','Hommes','Garçons','Filles','Adultes','Jeunes') NOT NULL,
`Cadre_Assemblage` varchar(10) NOT NULL,
`Guidon_Assemblage` varchar(10) NOT NULL,
`Freins_Assemblage` varchar(10) DEFAULT NULL,
`Selle_Assemblage` varchar(10) NOT NULL,
`DerailleurAvant_Assemblage` varchar(10) DEFAULT NULL,
`DerailleurArriere_Assemblage` varchar(10) DEFAULT NULL,
`RoueAvant_Assemblage` varchar(10) NOT NULL,
`RoueArriere_Assemblage` varchar(10) NOT NULL,
`Reflecteurs_Assemblage` varchar(10) DEFAULT NULL,
`Pedalier_Assemblage` varchar(10) NOT NULL,
`Ordinateur_Assemblage` varchar(10) DEFAULT NULL,
`Panier_Assemblage` varchar(10) DEFAULT NULL,
PRIMARY KEY (`ID_Assemblage`)
)
And here Bicyclette :
CREATE TABLE `Bicyclette` (
`ID_Bicyclette` int(11) NOT NULL AUTO_INCREMENT,
`ID_Assemblage` int(11) NOT NULL,
`Prix_Bicyclette` float NOT NULL,
`Categorie_Bicyclette` enum('VTT','Vélo de course','Classique','BMX') NOT NULL,
`DateIntroduction_Bicyclette` date NOT NULL,
`DateFin_Bicyclette` date NOT NULL,
`Nom_Bicyclette` varchar(255) DEFAULT NULL,
`Grandeur_Bicyclette`
enum('Dames','Hommes','Garçons','Filles','Adultes','Jeunes') DEFAULT NULL,
PRIMARY KEY (`ID_Bicyclette`),
KEY `ID_Assemblage` (`ID_Assemblage`),
CONSTRAINT `ID_Assemblage` FOREIGN KEY (`ID_Assemblage`) REFERENCES `Assemblage` (`ID_Assemblage`) ON DELETE CASCADE ON UPDATE CASCADE
)
Trigger Action :
I would like that when a new row is inserted into Bicyclette with as values :
the foreign key referring to a row of Assemblage
the values of the all the others attributes except 'Nom_Bicyclette' and 'Grandeur_Bicyclette' which will be null.
that a Trigger inserts 'Nom_Bicyclette' and 'Grandeur_Bicyclette' with the corresponding data from Assemblage thanks to the Foreign Key ID_Assemblage
Here is an example of inserting data into Bicyclette:
INSERT INTO Bicyclette VALUES (102, 547.8, "VTT", 01/01/2022, 01/01/2023)
Where 102 is the assembly model in the table Assemblage.
So i would like my Trigger to perform this action (for this example):
DECLARE #name VARCHAR
DECLARE #size VARCHAR
#name = SELECT Nom_Assemblage FROM Assemblage WHERE ID_Assemblage = 102
#size = SELECT Grandeur_Assemblage FROM Assemblage WHERE ID_Assemblage = 102
UPDATE Bicyclette SET Nom_Bicyclette=#name, Grandeur_Bicyclette=#size
WHERE ID_Bicyclette = INSERTED.ID_Bicyclette
Here is a diagram to better visualize the desired effect :
Schema for trigger
Thank you in advance for your help!
(It may seem special, but I have to have the fields 'Nom_Bicyclette' and 'Grandeur_Bicyclette' which correspond to the Foreign Key ID_Assemblage in my Bicyclette Table.)
create trigger Bicyclette_copy_attributes
before insert on Bicyclette
for each row begin
declare name varchar(255);
declare size varchar(255);
select Nom_Assemblage, Grandeur_Assemblage into name, size from Assemblage
where ID_Assemblage = NEW.ID_Assemblage;
set NEW.Nom_Bicyclette = name;
set NEW.Grandeur_Bicyclette = size;
end
In MySQL, there are differences in the syntax from other brands of SQL database:
DECLARE variables do not use the # sigil.
Use a BEFORE trigger if you need to change columns in the inserted row. If you write an AFTER trigger, it is too late, because the row has already been inserted.
Change columns with SET NEW.<column>, not UPDATE. The NEW keyword references the row that is about to be inserted.
All statements in the body of the trigger need to be terminated with a semicolon (;).
Also read https://dev.mysql.com/doc/refman/8.0/en/stored-programs-defining.html if you are using the MySQL client to execute the create trigger, so you understand how to set the delimiter.
Related
I currently build a database and write stored procedures for an Android app. I am long time programmer and created some databases years ago, but did not really work with stored procedures until now. The problem that I have at the moment is that I find no right way to check if a given string (specified by stringId) and a given language (specified by languageId) does not exist, and if a translated string already exists before I go on and insert a new translated string into the table TranslatedStrings. I looked up many similar questions and lots of other websites and although some seem to have had the exact same problem their solution did work for them but not for me.
Here is my current Create Procedure script:
create procedure `InsertTranslatedString`(in stringId int(10) unsigned, in translationSource tinyint(3) unsigned, in translationLanguageId int(10) unsigned,
in translatedString mediumtext, out insertedTranslatedStringId int(10) unsigned, out returnValue int(10))
reads sql data
modifies sql data
begin
-- if the string id does not exists
if (select count(1) from `Strings` where `stringId` = stringId) = 0
then
-- return error code
set returnValue = -1;
set insertedTranslatedStringId = 0;
-- if the language id does not exists
elseif (select count(1) from `Languages` where `languageId` = translationLanguageId) = 0
then
-- return error code
set returnValue = -2;
set insertedTranslatedStringId = 0;
-- if the translated string already exists
elseif (select count(1) from `TranslatedStrings` where `stringId` = stringId and `languageId` = translationLanguageId) > 0
then
-- return error code
set returnValue = -3;
set insertedTranslatedStringId = 0;
-- if we are ready to go
else
-- insert the actual translated string
insert into TranslatedStrings (`stringId`, `languageId`, `value`, `translationSource`, `createdDateTime`)
values (stringId, translationLanguageId, translatedString, translationSource, now());
select #newTranslatedStringId := last_insert_id();
-- give back output parameters
set insertedTranslatedStringId = #newTranslatedStringId;
set returnValue = 0;
end if;
end $$
The creation of the procedure works like charm.
I call the procedure with call InsertTranslatedString(76, 0, 1, 'German (Germany)', #insertedTranslatedStringId, #returnValue); Both stringId 76 and languageId 1 do not exist.
When I make this call I notice that the if-elseif-elseif-else block skips the first if (stringId check) even though it should enter its then block. The procedure however enters the first elseif (languageId check) which works fine.
I also tried out if-checks like these: if not exists (select 1 from 'Strings' where 'stringId' = stringId) but there the exists() function seemed to always return true not matter if the select returned a row or no row; the procedure would then skip right through to the second elseif just because I used a elseif exists (select... there. The actual select however does not return any row if I run it separately. Very confusing.
Here are the three referenced tables:
CREATE TABLE `Languages` (
`languageId` int(10) unsigned NOT NULL,
`nameStringId` int(10) unsigned NOT NULL,
`languageCode` varchar(5) DEFAULT NULL,
`hiddenInSettings` tinyint(1) DEFAULT '0',
PRIMARY KEY (`languageId`),
KEY `FK_Languages_nameStringId` (`nameStringId`),
CONSTRAINT `FK_Languages_nameStringId` FOREIGN KEY (`nameStringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all supported and automatically translated languages'
CREATE TABLE `Strings` (
`stringId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`originalValue` mediumtext NOT NULL,
`originalLanguageId` int(10) unsigned NOT NULL,
PRIMARY KEY (`stringId`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='contains all language-independent strings instances'
CREATE TABLE `TranslatedStrings` (
`stringId` int(10) unsigned NOT NULL,
`languageId` int(10) unsigned NOT NULL,
`value` mediumtext NOT NULL,
`translationSource` tinyint(3) unsigned DEFAULT '0',
`createdDateTime` datetime DEFAULT NULL,
`lastModifiedDateTime` datetime DEFAULT NULL,
`incorrectTranslationState` tinyint(3) unsigned DEFAULT '0',
`incorrectTranslationReporterId` int(10) unsigned DEFAULT NULL,
`incorrectTranslationReportedDateTime` datetime DEFAULT NULL,
PRIMARY KEY (`stringId`,`languageId`),
KEY `FK_TranslatedStrings_languageId` (`languageId`),
KEY `FK_TranslatedStrings_incorrectTranslationReporterId` (`incorrectTranslationReporterId`),
CONSTRAINT `FK_TranslatedStrings_incorrectTranslationReporterId` FOREIGN KEY (`incorrectTranslationReporterId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_languageId` FOREIGN KEY (`languageId`) REFERENCES `Languages` (`languageId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_stringId` FOREIGN KEY (`stringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all localized and automatically translated strings'
When I created the tables I did not create these KEY entries by the way, they were created by MySQL Server. Odd that they only resemble some of the CONSTRAINT entries and not all.
Since Strings only has a single-column primary key and no foreign keys I'm puzzled that its corresponding if-statement isn't triggered. What I am doing wrong?
I know that I can unchecked the 'safe update' mode but I want to understand why MySQL server returns this error even when all things look like correct?
I'm trying to call update procedure to update row in table country with statement
call sellcontroller.country_update(1, 'United Kingdom', 'GB', 'GBR', 'GBR');
but it throws an exception "Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column."
I'm definitely sure that I'm using a WHERE clause with table primary key and correct data type. And even more the same update statement used outside from procedure works correctly.
Code of the procedure is
CREATE PROCEDURE `country_update` (
in idCountry int(6),
in nameCountry varchar(255),
in codeISO2 varchar(2),
in codeISO3 varchar(3),
in codeCitizen varchar(5))
BEGIN
UPDATE `sellcontroller`.`country`
SET
`nameCountry` = nameCountry,
`codeISO2` = codeISO2,
`codeISO3` = codeISO3,
`codeCitizen` = codeCitizen
WHERE `idCountry` = idCountry;
END
The table creation statement for now is
CREATE TABLE `country` (
`idCountry` int(6) NOT NULL AUTO_INCREMENT,
`nameCountry` varchar(255) DEFAULT NULL,
`codeISO2` varchar(2) DEFAULT NULL,
`codeISO3` varchar(3) DEFAULT NULL',
`codeCitizen` varchar(5) DEFAULT NULL,
PRIMARY KEY (`idCountry`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
I have been successful in adding a new column to my table in MySQL. However I can't seem to add any data to it. I have tried using an UPDATE but I get an error. I am including the original code for the table, and the ALTER that added the column and the attempted update.
CREATE TABLE `Teams` (
`Team_id` INTEGER unsigned NULL AUTO_INCREMENT DEFAULT NULL,
`team name` VARCHAR(50) NULL DEFAULT NULL,
`league` CHAR(2) NULL DEFAULT NULL,
`div` VARCHAR(15) NULL DEFAULT NULL,
PRIMARY KEY (`Team_id`)
);
the filling (abbreviated)
INSERT INTO `Teams` (`team name`,`league`,`div`) VALUES
('Free Agent','',''),
('Blue Jays','AL','East'),
('Yankees','AL','East'),
('Orioles','AL','East'),
...and so on
The ALTER:
ALTER TABLE Teams
ADD City VARCHAR(20);
The UPDATE:
UPDATE Teams
SET City='NONE' where (team name='Free Agent');
You should escape identifiers if they contain spaces:
UPDATE `Teams`
SET `City`='NONE' where (`team name`='Free Agent');
I have a table in which there is a column name with SP varchar(10) NOT NULL. I want that column always to be unique so i created unique index on that column . My table schema as follows :
CREATE TABLE IF NOT EXISTS `tblspmaster` (
`CSN` bigint(20) NOT NULL AUTO_INCREMENT,
`SP` varchar(10) NOT NULL,
`FileImportedDate` date NOT NULL,
`AMZFileName` varchar(50) NOT NULL,
`CasperBatch` varchar(50) NOT NULL,
`BatchProcessedDate` date NOT NULL,
`ExpiryDate` date NOT NULL,
`Region` varchar(50) NOT NULL,
`FCCity` varchar(50) NOT NULL,
`VendorID` int(11) NOT NULL,
`LocationID` int(11) NOT NULL,
PRIMARY KEY (`CSN`),
UNIQUE KEY `SP` (`SP`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10000000000 ;
Now i want that if anybody tries to insert duplicate record then that record should be inserted into a secondary table name tblDuplicate.
I have gone through this question MySQL - ignore insert error: duplicate entry but i am not sure that instead of
INSERT INTO tbl VALUES (1,200) ON DUPLICATE KEY UPDATE value=200;
can i insert duplicate row into another table ?
what changes needed to be done in main table scheme or index column ?
**Note : Data will be inserted by importing excel or csv files and excel files generally contains 500k to 800 k records but there will be only one single column **
I believe you want to use a trigger for this. Here is the MySQL reference chapter on triggers.
Use a before insert trigger. In the trigger, check if the row is a duplicate (maybe count(*) where key column value = value to be inserted). If the row is a duplicate, perform an insert into your secondary table.
For the following table:
I'd like to add a constraint that if IsBanned flag is set to true, the BannedOn field cannot be left empty (cannot be set to null).
How can I do this in MySQL? Here's my CREATE syntax:
CREATE TABLE IF NOT EXISTS `fa_ranking_system`.`Player` (
`PlayerID` INT NOT NULL AUTO_INCREMENT,
`FK_ServerID` INT NOT NULL,
`PlayerName` VARCHAR(15) NOT NULL,
`RegDate` DATETIME NOT NULL,
`IsBanned` TINYINT(1) NOT NULL,
`LastUpdatedOn` DATETIME NOT NULL,
`LastUpdatedBy` VARCHAR(20) NOT NULL,
`BannedOn` DATETIME NULL,
PRIMARY KEY (`PlayerID`, `FK_ServerID`),
INDEX `fk_Player_Server_idx` (`FK_ServerID` ASC),
CONSTRAINT `fk_Player_Server`
FOREIGN KEY (`FK_ServerID`)
REFERENCES `fa_ranking_system`.`Server` (`ServerID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Actually, you can not define conditional structures in DDL syntax. Your field can be either NULL or NOT NULL - there's no third option (and it cannot depend of another field in structure)
But you can still emulate desired behavior via triggers. You can interrupt UPDATE/INSERT statement if incoming data is invalid in terms of your logic. That can be done via:
CREATE TRIGGER `bannedOnCheck`
BEFORE INSERT ON `fa_ranking_system`.`Player`
FOR EACH ROW
BEGIN
IF(new.IsBanned && new.BannedOn IS NULL) THEN
SIGNAL 'Integrity check failed: can not set banned without ban date'
END IF
END