Mysql Trigger Loop for query result with many rows - mysql

hi i have a database with many tables and foreign keys like this
CREATE TABLE IF NOT EXISTS `articulos` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nombre` varchar(63) NOT NULL,
`contenido` text NOT NULL,
`normas_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=138 ;
CREATE TABLE IF NOT EXISTS `aspectosambientales` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nombre` varchar(63) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=28 ;
CREATE TABLE IF NOT EXISTS `aspectosambientales_articulos` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`aspectosambientales_id` int(11) NOT NULL,
`articulos_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_aspaspectosambientales1` (`aspectosambientales_id`),
KEY `fk_aspee` (`articulos_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 UTO_INCREMENT=225 ;
CREATE TABLE IF NOT EXISTS `empresas` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`razonsocial` varchar(127) DEFAULT NULL,
`nit` varchar(63) DEFAULT NULL,
`direccion` varchar(127) DEFAULT NULL,
`telefono` varchar(15) DEFAULT NULL,
`web` varchar(63) DEFAULT NULL,
`auth_user_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
CREATE TABLE IF NOT EXISTS `articulos_empresas` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`empresas_id` int(11) NOT NULL,
`articulo_id` int(11) NOT NULL,
`acciones` text,
`responsable` varchar(255) DEFAULT NULL,
`plazo` date DEFAULT NULL,
`cumplido` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_normas_empresas_empresas1` (`empresas_id`),
KEY `fk_normas_empresas_normas1` (`normas_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
and i need to create a trigger to fill the 'articulos_empresas' after insert in 'empresas' for all rows in 'articulos' that match with 'aspectosambientals' that the new 'empresas' selected.
I get all 'articulos' with this query
SELECT articulos_id FROM aspectosambientales_articulos
WHERE aspectosambientales_id = ID
-- ID is the aspectosambientales_id selected when the 'empresas' row is created
-- maybe something like NEW.aspectosambientales_id
but i dont know how create a loop like ' for loop' in trigger for every result in the query
some like this:
CREATE TRIGGER 'filltableae' AFTER INSERT ON 'empresas'
FOR EACH ROW
BEGIN
DECLARE arrayresult = (SELECT articulos_id FROM aspectosambientales_articulos
WHERE aspectosambientales_id = NEW.aspectosambientales_id)
--- here is when i have to do the loop for all the results
--- for ids in arrayresults
--- insert into articulos_empresas ('',NEW.id, ids, '', '' ,'','')
--- endfor
END
thanks!!!

Based on #Razvan answer i left here the code for the trigger, so maybe can help somebody
DROP TRIGGER IF EXISTS AEINST;
DELIMITER //
CREATE TRIGGER AEINST AFTER INSERT ON procesos_aspectos
FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE ids INT;
DECLARE cur CURSOR FOR SELECT articulos_id FROM aspectosambientales_articulos WHERE aspectosambientales_id = NEW.aspectosambientales_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO ids;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO articulos_empresas VALUES (null,ids, NEW.empresas_id,null,null,null,null);
END LOOP;
CLOSE cur;
END; //
DELIMITER ;
thanks again!

As far as I know you can iterate through the result of a SELECT query using cursors.
See here : http://dev.mysql.com/doc/refman/5.0/en/cursors.html

Related

Process Multiple Row by a MYSQL Store Procedure

I am facing some trouble inserting data into a table by Store Procedure. Please allow me to explain in details.
I have a Three tables
CREATE TABLE `table_1` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`s_id` INT(11) NOT NULL,
`created` DATE NOT NULL,
`val` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
CREATE TABLE `table_2` (
`s_id` INT(11) NOT NULL AUTO_INCREMENT,
`t_id` INT(11) NOT NULL,
`p_id` INT(11) NOT NULL,
`d_id` INT(11) NOT NULL,
`created` DATE NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
CREATE TABLE `table_3` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`count` INT(11) NOT NULL,
`created` DATE NOT NULL,
`s_id` VARCHAR(255) NOT NULL,
`t_id` VARCHAR(255) NOT NULL,
`p_id` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`)
)
Is there any way to insert into 2nd table by store procedure using select statement. There will be multiple data as Select * from table_1; Then there will be a process like if(table_1.s_id == table_3.s_id) THEN UPDATE table_3 set count = count +1 ELSE INSERT into table_3 (s_id,t_id.....
Though I have tried using Cursor but its inserting only one record.
Here are the example of my usage of Cursor
DECLARE done INT DEFAULT FALSE;
DECLARE curs_count INT(11) DEFAULT 0;
DECLARE v_s_id BIGINT(20) DEFAULT 0;
DECLARE v_t_id BIGINT(20) DEFAULT 0;
DECLARE v_p_id BIGINT(20) DEFAULT 0;
DECLARE v_t_date BIGINT(20) DEFAULT 0;
DECLARE co_s_id BIGINT(20) DEFAULT 0;
DECLARE curs CURSOR FOR
SELECT
a.id,b.s_id,b.t_id,b.created
FROM
table_1 a
INNER JOIN table_2 b ON a.s_id = b.s_id
WHERE
a.val <> '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
DECLARE curs_id INT(11) DEFAULT 0;
OPEN curs;
SELECT FOUND_ROWS() INTO curs_count;
start_loop: loop
FETCH curs INTO curs_id,v_s_id,v_t_id,v_c_date;
IF done THEN
LEAVE start_loop;
END IF;
SELECT s_id INTO co_s_id FROM table_3;
IF co_s_id>0
THEN
update table_3 SET count = count+1 where s_id = co_s_id;
ELSE
INSERT INTO table_3 (support_id,track_id,track_date,count) VALUES (v_s_id,v_t_id,v_c_date,1);
END IF;
end loop;
CLOSE curs;
Can anyone help me out with this?
This code is running properly. The issue was infinite loop made the tables corrupted so no data were inserting.

Optimize MySQL trigger performance

I have following table structure. Added two triggers, but as the triggers work with string values and they search for string the database performance might degrade in future when every table will get huge. I have no strong experience with indexes, and don't know which fields to index to make trigger's search operation fast even with millions of rows.
What do you suggest?
CREATE TABLE `ofRoster` (
`rosterID` bigint(20) NOT NULL,
`username` varchar(64) NOT NULL,
`jid` varchar(1024) NOT NULL,
`sub` tinyint(4) NOT NULL,
`ask` tinyint(4) NOT NULL,
`recv` tinyint(4) NOT NULL,
`nick` varchar(255) DEFAULT NULL,
PRIMARY KEY (`rosterID`),
KEY `ofRoster_unameid_idx` (`username`),
KEY `ofRoster_jid_idx` (`jid`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ofUser` (
`username` varchar(64) NOT NULL,
`plainPassword` varchar(32) DEFAULT NULL,
`encryptedPassword` varchar(255) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`creationDate` char(15) NOT NULL,
`modificationDate` char(15) NOT NULL,
PRIMARY KEY (`username`),
KEY `ofUser_cDate_idx` (`creationDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
delimiter ;;
CREATE TRIGGER `UpdateNickOnInsert` BEFORE INSERT ON `ofRoster` FOR EACH ROW BEGIN
SET NEW.nick=(SELECT name FROM ofUser where username=NEW.username);
END
;;
delimiter ;
delimiter ;;
CREATE TRIGGER `UpdateRosterNicksOnUpdate` AFTER UPDATE ON `ofUser` FOR EACH ROW BEGIN
IF NEW.name <> OLD.name
THEN
UPDATE ofRoster r SET r.nick=NEW.name WHERE r.username=OLD.username;
END IF;
END
;;
delimiter ;

Create trigger on insert

I have the following table:
CREATE TABLE `loteria_loterias` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`fecha_ini` datetime NOT NULL,
`fecha_fin` datetime DEFAULT NULL,
`ganador` varchar(60) CHARACTER SET utf8 DEFAULT NULL,
`coste` int(11) NOT NULL,
`premium` int(11) NOT NULL,
`duracion` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `ganador` (`ganador`),
CONSTRAINT `loteria_loterias_ibfk_1` FOREIGN KEY (`ganador`) REFERENCES `tegm_users` (`user_login`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1
Is it posible to create a trigger that fill in 'fecha_fin' with 'fecha_ini + duracion' (duracion is in hours) in every insert?
delimiter |
CREATE TRIGGER `some_name` BEFORE INSERT ON loteria_loterias
FOR EACH ROW BEGIN
SET NEW.fecha_fin = NEW.fecha_ini + interval NEW.duracion hour;
END;
|
delimiter ;

MySql - can BEFORE INSERT TRIGGER insert into 2 columns?

Can this trigger be changed so that the sortorder table gets 2 column values (sortOrderId, sortOrder) inserted?
How is the value of sortOrder found?
If it is known and can be inserted into image table then can it also be inserted into the sortorder table?
-- Trigger DDL Statements
DELIMITER $$
USE `nextcart`$$
CREATE
DEFINER=`root`#`localhost`
TRIGGER `nextcart`.`insert_sortorderid`
BEFORE INSERT ON `nextcart`.`image`
FOR EACH ROW
BEGIN
INSERT INTO sortorder SET sortOrderId = NULL, sortOrder = NEW.sortOrder;
SET NEW.sortOrderId = (SELECT LAST_INSERT_ID());
END;
$$
CREATE TABLE sortorder:
delimiter $$
CREATE TABLE `sortorder` (
`sortOrderId` int(11) NOT NULL AUTO_INCREMENT,
`sortOrder` tinyint(4) NOT NULL,
PRIMARY KEY (`sortOrderId`),
KEY `sort_order` (`sortOrderId`,`sortOrder`),
CONSTRAINT `fk_sortOrderId` FOREIGN KEY (`sortOrderId`) REFERENCES `image` (`imageId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8$$
CREATE TABLE image:
delimiter $$
CREATE TABLE `image` (
`imageId` int(11) NOT NULL AUTO_INCREMENT,
`imageFileName` varchar(45) DEFAULT NULL,
`imagePath` varchar(255) DEFAULT NULL,
`imageTitle` varchar(100) DEFAULT NULL,
`imageAlt` varchar(100) DEFAULT NULL,
`imageWidth` int(11) DEFAULT NULL,
`imageHeight` int(11) DEFAULT NULL,
`classId` int(11) DEFAULT NULL,
`imageSizeId` tinyint(4) NOT NULL,
`isImageEnabled` bit(1) DEFAULT b'0',
`sortOrderId` int(11) DEFAULT NULL,
PRIMARY KEY (`imageId`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8$$
ERROR MESSAGE:
Error 1054: Unknown column 'sortOrder' in 'NEW' SQL Statement:
CREATE TRIGGER insert_sortorderid BEFORE INSERT ON image FOR EACH
ROW BEGIN INSERT INTO nextcart.sortorder SET sortOrderId = NULL,
sortOrder = NEW.sortOrder; SET NEW.sortOrderId = ( SELECT
LAST_INSERT_ID()); END; Error when running failback script. Details
follow. Error 1050: Table 'image' already exists SQL Statement: CREATE
TABLE image ( imageId int(11) NOT NULL AUTO_INCREMENT,
imageFileName varchar(45) DEFAULT NULL, imagePath varchar(255)
DEFAULT NULL, imageTitle varchar(100) DEFAULT NULL, imageAlt
varchar(100) DEFAULT NULL, imageWidth int(11) DEFAULT NULL,
imageHeight int(11) DEFAULT NULL, classId int(11) DEFAULT NULL,
imageSizeId tinyint(4) NOT NULL, isImageEnabled bit(1) DEFAULT
b'0', sortOrderId int(11) DEFAULT NULL, PRIMARY KEY (imageId)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
There is no column named sortOrder in the image table.
So, the reference to NEW.sortOrder (on the insert statement in the trigger) is invalid.
To answer your first question: No. Since there is no value supplied for that in the INSERT statement (which fires the BEFORE INSERT TRIGGER), you don't really have a source for that value.
The easy option is to provide a default value for it.
If you want to supply a value for the sortOrder column, then one option is to add a sortOrder column to the image table, and then the value can be supplied in the INSERT INTO image statement. Then it would available in the trigger.
(The purpose of the sortorder table is not at all clear.)

MySQL ALBUM <- ALBUM_PHOTO -> PHOTO database model, foreign key with trigger, who's first?

I'd trying to create a ALBUM <- ALBUM_PHOTO -> PHOTO database model with MySQL.
and of course, I want to update these 3 tables synchronously, like when I insert into ALBUM_PHOTO, also insert into ALBUM and PHOTO with corresponding values.
But when I add triggers, the order of them made me confused and finally I got this method, like below:
-- --------------------------------------------------------
--
-- TABLE `user_album`
--
CREATE TABLE IF NOT EXISTS `user_album` (
`album_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`album_name` varchar(45) NOT NULL,
`cover_id` int(11) NOT NULL,
`numbers_of_photo` int(11) NOT NULL,
`album_desc` varchar(45) DEFAULT NULL,
`album_path` varchar(45) DEFAULT NULL,
`addtime` datetime NOT NULL,
PRIMARY KEY (`album_id`,`user_id`),
KEY `fk_album_user_id_idx` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- TRIGGER `user_album`
--
DROP TRIGGER IF EXISTS `tg_album_insert`;
DELIMITER //
CREATE TRIGGER `tg_album_insert` AFTER INSERT ON `user_album`
FOR EACH ROW BEGIN
UPDATE USER_ALBUM SET NUMBERS_OF_PHOTO = 0
WHERE ALBUM_ID = NEW.ALBUM_ID;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `tg_album_update_then_delete`;
DELIMITER //
CREATE TRIGGER `tg_album_update_then_delete` AFTER UPDATE ON `user_album`
FOR EACH ROW BEGIN
DELETE FROM USER_ALBUM
WHERE ALBUM_ID = NEW.ALBUM_ID AND NEW.NUMBERS_OF_PHOTO <= 0;
END
//
DELIMITER ;
-- --------------------------------------------------------
--
-- TABLE `user_photo`
--
CREATE TABLE IF NOT EXISTS `user_photo` (
`photo_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`thumbnail_id` int(11) NOT NULL,
`photo_name` varchar(45) DEFAULT NULL,
`addtime` datetime NOT NULL,
`photo_path` varchar(45) NOT NULL,
PRIMARY KEY (`photo_id`),
KEY `fk_photo_user_id_idx` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- TABLE `user_album_photo`
--
CREATE TABLE IF NOT EXISTS `user_album_photo` (
`photo_id` int(11) NOT NULL AUTO_INCREMENT,
`album_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`photo_name` varchar(45) DEFAULT NULL,
`desc` varchar(45) DEFAULT NULL,
`tag` varchar(45) DEFAULT NULL,
PRIMARY KEY (`photo_id`),
KEY `fk_album_photo_photo_id_idx` (`photo_id`),
KEY `fk_album_photo_album_id_idx` (`album_id`),
KEY `fk_album_photo_user_id_idx` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
--
-- TRIGGER `user_album_photo`
--
DROP TRIGGER IF EXISTS `tg_album_photo_delete`;
DELIMITER //
CREATE TRIGGER `tg_album_photo_delete` AFTER DELETE ON `user_album_photo`
FOR EACH ROW BEGIN
DELETE FROM USER_PHOTO WHERE PHOTO_ID = OLD.PHOTO_ID;
UPDATE USER_ALBUM SET NUMBERS_OF_PHOTO = NUMBERS_OF_PHOTO-1
WHERE ALBUM_ID=OLD.ALBUM_ID;
END
//
DELIMITER ;
DROP TRIGGER IF EXISTS `tg_album_photo_insert`;
DELIMITER //
CREATE TRIGGER `tg_album_photo_insert` AFTER INSERT ON `user_album_photo`
FOR EACH ROW BEGIN
IF NOT EXISTS (SELECT * FROM `user_album` WHERE ALBUM_ID = NEW.ALBUM_ID) THEN
INSERT INTO USER_ALBUM VALUES(NEW.ALBUM_ID, UEW.USER_ID);
ELSE
UPDATE USER_ALBUM SET NUMBERS_OF_PHOTO=NUMBERS_OF_PHOTO+1
WHERE ALBUM_ID = NEW.ALBUM_ID;
END IF;
INSERT INTO USER_PHOTO VALUES(NEW.PHOTO_ID, NEW.USER_ID);
END
//
DELIMITER ;
But now, the question is, I added foreign key constraint in USER_ALBUM_PHOTO TABLE, but when inserting a record, it is firstly inserted into USER_ALBUM_PHOTO when there isn't the corresponding record in the other 2 tables.
So, do I need to add the constraint into the other 2 tables instead of USER_ALBUM_PHOTO, maybe like PHOTO >- ALBUM_PHOTO <- ALBUM ?
Or there must be sth. wrong in my triggers.
Thx!