This stored procedure should insert an entry after a SELECT for a foreign key. Currently, It does nothing. When I CALL it, it won't give me an error or anything and won't insert the record either.
Can I even do multiple things (SELECT, UPDATE, INSERT..) in a single procedure? If yes, what am I missing here? If there is an error while running one of the (update/insert/select)s, should I get an error?
DELIMITER $$
CREATE PROCEDURE `InserAndAttachReferencia` (
IN refereciaText VARCHAR(45),
IN attachTo INT unsigned,
OUT insid INT unsigned
)
BEGIN
-- SELECT THE REP_ID
DECLARE attachToRepID INT UNSIGNED DEFAULT 0;
SELECT id
INTO attachToRepID
FROM AlkReferencia
WHERE id=attachTo;
-- INSERTING THE NEW ENTRY WITH GIVEN REP_ID
INSERT INTO AlkReferencia (id,rep_id,csatolva_id,referencia)
VALUES(null,attachToRepID,attachTo,referenciaText);
SET insid = LAST_INSERT_ID();
END
Edit.:
Yeah, the last update is useless here, should just set the rep_id while inserting, but it is not the issue here. (Copied from one of my other procedure, when I need the last update...)..Fixed in the question.
Table:
-- -----------------------------------------------------
-- Table `AlkatreszDb`.`AlkReferencia`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `AlkatreszDb`.`AlkReferencia` ;
CREATE TABLE IF NOT EXISTS `AlkatreszDb`.`AlkReferencia` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`rep_id` INT UNSIGNED NULL,
`csatolva_id` INT UNSIGNED NULL,
`referencia` VARCHAR(45) NOT NULL,
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NULL,
PRIMARY KEY (`id`),
INDEX `fk_AlkReferencia_AlkReferencia1_idx` (`rep_id` ASC),
INDEX `fk_AlkReferencia_AlkReferencia2_idx` (`csatolva_id` ASC),
CONSTRAINT `fk_AlkReferencia_AlkReferencia1`
FOREIGN KEY (`rep_id`)
REFERENCES `AlkatreszDb`.`AlkReferencia` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_AlkReferencia_AlkReferencia2`
FOREIGN KEY (`csatolva_id`)
REFERENCES `AlkatreszDb`.`AlkReferencia` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
This is unlikely to fix your problem, but you can simplify the code to:
INSERT INTO AlkReferencia(rep_id, csatolva_id, referencia)
SELECT ar.id, attachTo, referenciaText
FROM AlkReferencia ar
WHERE ar.id = attachTo;
I would also prepend the variable names with v_ (or something) to distinguish them from column names. That is often a source of errors in stored procedures:
INSERT INTO AlkReferencia(rep_id, csatolva_id, referencia)
SELECT ar.id, v_attachTo, v_referenciaText
FROM AlkReferencia ar
WHERE ar.id = v_attachTo;
EDIT:
This code is quite suspicious:
SELECT id
INTO attachToRepID
FROM AlkReferencia
WHERE id = attachTo;
Why not just use attachTo? Do you intend for one of the references to really be csatolva_id?
You say that your code is outputting nothing. Have you tried EXEC the procedure with parameters?
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 have multiple tables in this database; two of which are involved with this trigger
create table shipment_item(
shipmentID int not null,
shipmentItemID int not null,
purchaseID int not null,
insuredValue decimal(5,2) not null,
constraint shipment_ItemPK primary key(shipmentID, shipmentItemID),
constraint shipmentFK foreign key(shipmentID)
references shipment(shipmentID)
on delete cascade,
constraint purchaseFK foreign key(purchaseID)
references purchase(purchaseID)
);
create table purchase(
purchaseID int not null auto_increment,
storeID int not null,
purchaseDate date not null,
description char(30) not null,
category char(30) not null,
price decimal(5,2) not null,
constraint purchasePK primary key(purchaseID),
constraint storeFK foreign key(storeID)
references store(storeID)
);
I'm trying to implement a trigger in my MySQL database. That trigger looks like this
DELIMITER //
CREATE TRIGGER checkInsuranceTrigger
BEFORE INSERT ON shipment_item
FOR EACH ROW BEGIN
IF(shipment_item.insuredValue <= purchase.price) THEN
SET NEW.insuredValue = purchase.price;
END IF;
END
//
DELIMITER ;
When I implement this trigger and then try to insert data into the shipment_item table I get the following error
Error Code 1109: Unknown Table 'shipment_item' in field list
Reference the column in the row being inserted with the NEW keyword, like you did on the SET statement.
To reference values from rows in other tables, you need a SQL statement, in your case, looks like you want a SELECT.
For example (following the outline of the logic in your trigger), something like this:
BEGIN
-- local variable
DECLARE ln_purchase_price DECIMAL(5,2);
-- populate local variable (this is just an example of one way to do this)
SELECT p.price
INTO ln_purchase_price
FROM purchase p
WHERE p.purchaseID = NEW.purchaseID
LIMIT 1;
-- compare value from row to local variable
IF (NEW.insuredValue <= ln_purchase_price) THEN
SET NEW.insuredValue = ln_purchase_price;
END IF;
May I suggest verifying that the table really exists in the same database as the trigger itself?
I've got this mysql table:
CREATE TABLE IF NOT EXISTS `activities` (
`id` INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` CHAR(255) NOT NULL,
`status` ENUM('open','progress','close'),
`date_begin` DATE,
`date_finish` DATE,
`progress` TINYINT,
`reliance` INTEGER,
`parent` INTEGER,
FOREIGN KEY(owner) REFERENCES users(id) ON UPDATE CASCADE ON DELETE SET NULL,
FOREIGN KEY(reliance) REFERENCES activities(id) ON UPDATE CASCADE ON DELETE SET NULL,
FOREIGN KEY(parent) REFERENCES activities(id) ON UPDATE CASCADE ON DELETE SET NULL
)ENGINE = INNODB;
My problem is when i want to update the date_begin of one activity. Infact i would like to update the date of begin of all activities that are reliant or child of the updated activity.
Can i force mysql to create a recursive trigger?
Something like this should work, at least if you're on a recent version of MySQL:
delimiter |
CREATE TRIGGER activitiesUpdateReliantAndChildren BEFORE UPDATE ON 'activities'
FOR EACH ROW
BEGIN
update 'activities'
set date_begin = NEW.date_begin
where reliance = NEW.id;
update 'activities'
set date_begin = NEW.date_begin
where parent = NEW.id;
END;
|
delimiter ;
Although the trigger may work...it is not a good practice to create recursive triggers! and if u thing you must... then think not only twice but 100times before applying! They can result in more harm than good sometimes.
I'm a MySQL newbie, I just discovered that it doesn't support assertions.
I got this table:
CREATE TABLE `guest` (
`ssn` varchar(16) NOT NULL,
`name` varchar(200) NOT NULL,
`surname` varchar(200) NOT NULL,
`card_number` int(11) NOT NULL,
PRIMARY KEY (`ssn`),
KEY `card_number` (`card_number`),
CONSTRAINT `guest_ibfk_1` FOREIGN KEY (`card_number`) REFERENCES `member` (`card_number`)
)
What I need is that a member can invite maximum 2 guests.
So, in table guest I need that a specific card_number can appear maximum 2 times.
How can I manage it without assertions?
Thanks.
This definitly smells of a BEFORE INSERT trigger on the table 'guest':
DELIMITER $$
DROP TRIGGER IF EXISTS check_guest_count $$
CREATE TRIGGER check_guest_count BEFORE INSERT ON `guest`
FOR EACH ROW BEGIN
DECLARE numguests int DEFAULT 0;
SELECT COUNT(*) INTO numguests FROM `guest` WHERE card_number=NEW.card_number;
if numguests>=2 THEN
SET NEW.card_number = NULL;
END IF;
END;
$$
DELIMITER ;
This basically looks up the current guest count, and if it is already >=2 sets card_number to NULL. Since card_number is declared NOT NULL, this will reject the insert.
Tested and works for me on MySQL 5.1.41-3ubuntu12.10 (Ubuntu Lucid)
this is my tables
CREATE TABLE IF NOT EXISTS `carslibrary` (
`CarID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CarName` varchar(255) NOT NULL,
PRIMARY KEY (`CarID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
CREATE TABLE IF NOT EXISTS `colorslibrary` (
`ColorID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ColorName` varchar(255) NOT NULL,
PRIMARY KEY (`ColorID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
CREATE TABLE IF NOT EXISTS `facerecord` (
`carslibrary_ID` int(10) unsigned NOT NULL,
`colorslibrary_ID` int(11) unsigned NOT NULL,
KEY `carslibrary_ID` (`carslibrary_ID`),
KEY `colorslibrary_ID` (`colorslibrary_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
i noticed carslibrary_ID attribute inside facerecord table is not automatically updated when i add a car record inside carslibrary table, what should i do to be able to?
Firstly, you'll need to have a default value specified for the facerecord.colorslibrary_ID since you will not 'know' what it is when inserting into the carslibrary table. That said you could alter your DDL for the facerecord table to be:
CREATE TABLE `facerecord` (
`carslibrary_ID` int(10) unsigned NOT NULL,
`colorslibrary_ID` int(10) unsigned NOT NULL DEFAULT '0',
KEY `carslibrary_ID` (`carslibrary_ID`),
KEY `colorslibrary_ID` (`colorslibrary_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I've also changed the datatype of the colorslibrary_ID column to match that of the colorslibrary.ColorID column in case you ever feel like setting up a foreign key between facerecord.colorslibrary_ID and colorslibrary.ColorID ;). For the sake of completeness you should insert a row into the colorslibrary table with a ColorID = 0. Hence:
insert into `colorslibrary` (ColorName) values ('unknown color');
update `colorslibrary` set ColorID = 0 where ColorName = 'unknown color';
Then you can go ahead and define your trigger to insert into the facerecord table:
delimiter $$
CREATE TRIGGER carslibrary_trigger
AFTER insert ON carslibrary
FOR EACH ROW
BEGIN
insert into facerecord (carslibrary_ID) values (new.CarID);
END$$
delimiter;
All new rows inserted into the facerecord table will then be inserted with a colorslibrary_ID that relates to the 'unknown color' colorslibrary.ColorName.You can then manually update the facerecord.colorslibrary_ID as and when you know it.
Good luck!
PS If you need to remove any existing AFTER insert triggers from the carslibrary table you can do so by firstly finding the existing triggers:
select trigger_name
from information_schema.triggers
where event_object_table = 'carslibrary'
and action_timing = 'AFTER'
and event_manipulation= 'INSERT';
Then take the name of the trigger returned by the above statement (lets say the string 'carslibrary_trigger' is returned) and run:
drop trigger carslibrary_trigger;
Then re-run the CREATE TRIGGER script.
Once a trigger is set up it will automatically perform the action you have specified when the trigger action you have specified occurs. In this case we are telling the database "after an insert happens into the carslibrary table automatically insert a row into the facerecord table using the CarID of the new carslibrary row to populate the facerecord.carslibrary_ID column". As with most things the best way is to try it! Once you have created the trigger manually insert a new row into the 'carslibrarytable. Now look at the data in thefacerecord` table - you should see a new row that has been inserted by the trigger firing.
It sounds like you would benefit from learning about triggers. I recommend the docs on the MySQL site because this answer is way longer than I first intended it to be!
You will need to use triggers. See http://dev.mysql.com/doc/refman/5.0/en/triggers.html