Mysql use LAST_INSERT_ID in stored procedure - mysql

I need to create a table based on the last id inserted into another main table, for this I created the following stored procedure:
CREATE PROCEDURE `sp_create_campaign`
(
IN p_vName VARCHAR(70),
IN p_iIdOper INT(11),
IN p_iIdCount INT(11),
IN p_iIdMoney INT(11),
IN p_cPrefix CHAR(2),
IN p_tComment TINYTEXT,
IN p_iIdUser VARCHAR(32),
OUT p_return_code TINYINT UNSIGNED
)
BEGIN
DECLARE p_campaign INT(11);
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
set p_return_code = 1;
rollback;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
set p_return_code = 2;
rollback;
END;
START TRANSACTION;
-- Campaign
INSERT INTO `db_campaign`
(`vName`, `iIdOper`, `iIdCount`, `iIdMoney`, `cPrefix`, `tComment`, `iIdUser`, `dRegister`)
VALUES
(p_vName, p_iIdOper, p_iIdCount, p_iIdMoney, p_cPrefix, p_tComment, p_iIdUser, NOW());
SET p_campaign := LAST_INSERT_ID();
-- Sales
SET #s = CONCAT('DROP TABLE IF EXISTS ', 'db_sale_', p_campaign);
PREPARE stm FROM #s;
EXECUTE stm;
SET #x = CONCAT(
'CREATE TABLE ',
'db_sale_', p_campaign,
"(
`iIdSale` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`dDate` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
`dSubtotal` DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
`dTax` DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
`dTotal` DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
`iIdMoney` INT(11) UNSIGNED NOT NULL,
`iIdOper` INT(11) UNSIGNED NOT NULL,
`iIdBankCount` INT(11) UNSIGNED NOT NULL,
`iIdGroup` INT(11) UNSIGNED NOT NULL,
`iIdUser` INT(11) UNSIGNED NOT NULL,
`iIdUserReg` VARCHAR(32) NOT NULL,
`dRegister` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`iIdSale`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;");
PREPARE stm FROM #x;
EXECUTE stm;
COMMIT;
-- SUCCESS
set p_return_code = 0;
END
But the problem is that only inserts the first record and fails to create the table. Where am I failing?

Replace this line: SET p_campaign := LAST_INSERT_ID();
With this one: SELECT LAST_INSERT_ID() INTO p_campaign ;

if you use SET you need = instead of :=

Two things:
Executing DROP will implicitly COMMIT your transaction.
Try adding
DEALLOCATE PREPARE stm;
after each EXECUTE statement.

According to MySQL documentation of last_insert_id()
If a stored procedure executes statements that change the value of LAST_INSERT_ID(), the changed value is seen by statements that follow the procedure call.
Use something like:
SELECT id INTO p_campaign FROM db_campaign ORDER BY id DESC LIMIT 1;
Or:
SELECT max(id) INTO p_campaign FROM db_campaign;

Related

MySQL Stored Procedure running slow in PhpMyAdmin but fast in Workbench

I have created a stored procedure in MySQL which calls a view to fetch results.
I have executed the stored procedure in MySQL Workbench and its executing in 5 secs.
However, when I run the same in phpMyAdmin it takes 50 seconds.
I have researched and founded that collation of the table columns takes time for that i used the Convert() method on the column but didnt work.
Can anyone help?
Table Schema:
CREATE TABLE `inspection_transactions` (
`id` int NOT NULL,
`point_id` int DEFAULT NULL,
`inspection_id` int DEFAULT NULL,
`instruction_pool_id` int DEFAULT NULL,
`inspection_date` datetime DEFAULT NULL,
`user_id` int DEFAULT NULL,
`result` varchar(255) DEFAULT NULL,
`comment` varchar(255) DEFAULT NULL,
`comment2` varchar(255) DEFAULT NULL,
`inspection_company_transaction_id` int DEFAULT NULL,
`inspection_type` int DEFAULT NULL COMMENT '1:Single, 2:Company, 3:Home '
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
** View **
CREATE
ALGORITHM = UNDEFINED
DEFINER = `hms`#`localhost`
SQL SECURITY DEFINER
VIEW `testingdump`.`inspection_transactions_company_number_grouped_view` AS
SELECT
`inspection_transactions_company_number_view`.`point_id` AS `point_id`,
`inspection_transactions_company_number_view`.`point_name` AS `point_name`,
MONTH(`inspection_transactions_company_number_view`.`inspection_date`) AS `month`,
`inspection_transactions_company_number_view`.`inspection_date` AS `inspection_date`,
`inspection_transactions_company_number_view`.`inspection_id` AS `inspection_id`,
`inspection_transactions_company_number_view`.`instruction_pool_id` AS `instruction_pool_id`,
`inspection_transactions_company_number_view`.`inspection_company_transaction_id` AS `inspection_company_transaction_id`,
`inspection_transactions_company_number_view`.`customer_id` AS `customer_id`,
CONCAT(SUBSTR(`inspection_transactions_company_number_view`.`instruction_pool_name`,
1,
3),
' ',
SUM(`inspection_transactions_company_number_view`.`result`)) AS `result_concat`,
SUM(`inspection_transactions_company_number_view`.`result`) AS `result`,
`inspection_transactions_company_number_view`.`instruction_pool_name` AS `instruction_pool_name`
FROM
`testingdump`.`inspection_transactions_company_number_view`
GROUP BY `inspection_transactions_company_number_view`.`point_id` , `inspection_transactions_company_number_view`.`instruction_pool_id` , MONTH(`inspection_transactions_company_number_view`.`inspection_date`) , `inspection_transactions_company_number_view`.`inspection_company_transaction_id`
ORDER BY `inspection_transactions_company_number_view`.`point_id` , `inspection_transactions_company_number_view`.`instruction_pool_id` , MONTH(`inspection_transactions_company_number_view`.`inspection_date`);
** Stored Procedure **
DELIMITER $$
CREATE DEFINER=`hms`#`localhost` PROCEDURE `company_transactions_number_monthly_pivot`(IN cus_id INT, IN insp_id INT, IN start_date datetime, IN end_date datetime)
BEGIN
SET #sql = NULL;
DROP TABLE IF EXISTS tbl1;
CREATE TEMPORARY TABLE tbl1 AS
( SELECT point_id,point_name, instruction_pool_id, instruction_pool_name, month, convert(result using utf8) collate utf8_general_ci
FROM `inspection_transactions_company_number_grouped_view`
WHERE `customer_id` = cus_id AND `inspection_id` = insp_id and `inspection_date` > start_date and `inspection_date` < end_date
);
SET #sql = CONCAT('SELECT point_name, ', #sql, ' FROM tbl1 GROUP BY point_id');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

Stored procedure for copying data

I am all new to creating procedures and triggers in MySQL, but have struggled with this over the last couple of days, and it simply will not work. The error messages, that I get from Mysql does not help me any longer.
So I am trying to create a procedure, which I need to run after an update. I will take any updates and store new data in a dynamic created table in another database.
Here it is:
CREATE PROCEDURE get_price_storage_table (IN market_id INT(11), OUT tablename VARCHAR(50))
BEGIN
SET #NUMBER = CEILING(market_id / 100000) * 100000;
SET tablename = CONCAT('price_',#NUMBER);
SET #SQL = CONCAT('CREATE TABLE IF NOT EXISTS data.',tablename,'(
`pk_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`fk_market_id` INT(11) UNSIGNED NOT NULL,
`fk_outcome_type_id` MEDIUMINT(8) UNSIGNED NOT NULL,
`price` DOUBLE NOT NULL,
`status` ENUM(\'enabled\',\'disabled\') NOT NULL,
`created` DATETIME NOT NULL,
PRIMARY KEY (`pk_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8')');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
This need to be triggered after update, where the SQL goes like:
CREATE TRIGGER copy_price_data AFTER UPDATE ON price
FOR EACH ROW
BEGIN
IF NEW.updated <> OLD.updated THEN
SET #market_id = NEW.fk_market_id;
SET #tablename = NULL;
CALL create_price_storage_table(#market_id, #tablename);
SELECT #tablename;
SET #SQL = CONCAT(
'INSERT INTO ',
#tablename,
' (`fk_market_id`, `fk_outcome_type_id`, `price`, `status`, `created`) VALUES (NEW.fk_market_id, NEW.fk_outcome_type_id, NEW.price, NEW.status, NOW())');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END;
When trying to create the procedure, then I get the following error message from MySQL:
CREATE PROCEDURE get_price_storage_table (IN market_id INT(11), OUT tablename VARCHAR(50))
BEGIN
SET #NUMBER = CEILING(market_id / 100000) * 100000;
MySQL returnerede: Dokumentation 1064 - You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near '' at line 3
I hope someone with greater understanding than me, can point me in the right direction. Thanks.
Change:
CREATE PROCEDURE get_price_storage_table (IN market_id INT(11), OUT tablename VARCHAR(50))
BEGIN
SET #NUMBER = CEILING(market_id / 100000) * 100000;
SET tablename = CONCAT('price_',#NUMBER);
SET #SQL = CONCAT('CREATE TABLE IF NOT EXISTS data.',tablename,'(
`pk_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`fk_market_id` INT(11) UNSIGNED NOT NULL,
`fk_outcome_type_id` MEDIUMINT(8) UNSIGNED NOT NULL,
`price` DOUBLE NOT NULL,
`status` ENUM(\'enabled\',\'disabled\') NOT NULL,
`created` DATETIME NOT NULL,
PRIMARY KEY (`pk_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8')');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;
By:
CREATE PROCEDURE `get_price_storage_table`(`market_id` INT UNSIGNED, OUT `tablename` VARCHAR(50))
BEGIN
DECLARE `NUMBER` INT UNSIGNED;
SET `NUMBER` := CEILING(`market_id` / 100000) * 100000;
SET `tablename` := CONCAT('`price_', NUMBER, '`');
SET #`SQL` := CONCAT('CREATE TABLE IF NOT EXISTS ', tablename, '(
`pk_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`fk_market_id` INT(11) UNSIGNED NOT NULL,
`fk_outcome_type_id` MEDIUMINT(8) UNSIGNED NOT NULL,
`price` DOUBLE NOT NULL,
`status` ENUM(\'enabled\',\'disabled\') NOT NULL,
`created` DATETIME NOT NULL,
PRIMARY KEY (`pk_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8');
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8')');
PREPARE `stmt` FROM #`SQL`;
EXECUTE `stmt`;
DEALLOCATE PREPARE `stmt`;
END//
Example:
mysql> DROP PROCEDURE IF EXISTS `get_price_storage_table`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `get_price_storage_table`(`market_id` INT UNSIGNED, OUT `tablename` VARCHAR(50))
-> BEGIN
-> DECLARE `NUMBER` INT UNSIGNED;
-> SET `NUMBER` := CEILING(`market_id` / 100000) * 100000;
-> SET `tablename` := CONCAT('`price_', NUMBER, '`');
-> SET #`SQL` := CONCAT('CREATE TABLE IF NOT EXISTS ', tablename, '(
> `pk_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
> `fk_market_id` INT(11) UNSIGNED NOT NULL,
> `fk_outcome_type_id` MEDIUMINT(8) UNSIGNED NOT NULL,
> `price` DOUBLE NOT NULL,
> `status` ENUM(\'enabled\',\'disabled\') NOT NULL,
> `created` DATETIME NOT NULL,
> PRIMARY KEY (`pk_id`)
> ) ENGINE=InnoDB DEFAULT CHARSET=utf8');
-> PREPARE `stmt` FROM #`SQL`;
-> EXECUTE `stmt`;
-> DEALLOCATE PREPARE `stmt`;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `get_price_storage_table`(1, #`tablename`);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #`tablename`;
+----------------+
| #`tablename` |
+----------------+
| `price_100000` |
+----------------+
1 row in set (0.00 sec)
mysql> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| price_100000 |
+----------------+
1 row in set (0.00 sec)
Syntax errors are to be located to the left (or above) of the place reported in the error message, since the reported place is the first thing that confuses MySQL.
In your case this is the ;
It finishes your CREATE PROCEDURE statement, but MySQL expects more to come, like an END.
Procedures / Triggers / Functions have to be declared with a different delimiter when they consist of more than one statement.
Try like this:
DELIMITER $$
CREATE PROCEDURE whatever()
BEGIN
SELECT 'whatever';
SELECT 'another';
END $$
DELIMITER ;

syntax error in mysql procedure error code 1064

I am trying to write one procedure, i am getting syntax error. I was trying to fix the same with the help of net, but failed.
Here is my stored procedure. Any help please?
The scenario is i am trying to take workspaceid column values from table hotelings and trying to make that value as my column for another table. Then i am trying to update the same column value with ; for a given start and end time of hoteling table in newly created table2.
My two tables are
CREATE TABLE `hotelings` (
`HotelingId` int(11) NOT NULL AUTO_INCREMENT,
`Description` longtext,
`StartDate` datetime NOT NULL,
`EndDate` datetime NOT NULL,
`BookedBy` longtext,
`BookingType` int(11) NOT NULL,
`RepeatType` longtext,
`RepeatDay` longtext,
`ProjectId` int(11) NOT NULL,
`WorkSpaceId` int(11) NOT NULL,
`starttime` varchar(45) DEFAULT NULL,
`endtime` varchar(45) DEFAULT NULL,
PRIMARY KEY (`HotelingId`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE `hotelingtime` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Time` time DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
and my procedure is:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `new_procedure`()
BEGIN
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN workspaceid = ''',
workspaceid,
''' then "" ELSE NULL end) AS ',
CONCAT('`',workspaceid,'`')
)
) INTO #sql
FROM sms.hotelings;
SET #sql = CONCAT('CREATE TABLE IF NOT EXISTS table2 AS SELECT t.Time as Time, ', #sql, ' FROM sms.hotelings h, sms.hotelingtime t
GROUP BY t.Time');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
begin
declare num_rows int;
declare i int;
declare col_name varchar(50);
declare v varchar(10);
DECLARE v_finished INTEGER DEFAULT 0;
-- cursor to fetch column names
DECLARE col_names CURSOR FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'table2'
ORDER BY ordinal_position;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN col_names;
temp_hotelingloop: LOOP
FETCH col_names INTO col_name;
IF v_finished = 1 THEN
LEAVE temp_hotelingloop;
END IF;
begin
declare starttime time;
declare endtime time;
-- cursor to fetch start and end for a given workspaceid
DECLARE startendTime CURSOR FOR
SELECT starttime, endtime from hotelings
where workspaceid = col_name;
OPEN startendTime;
FETCH startendTime INTO starttime, endtime;
-- i am getting error here and not giving me the result.
SET #sql = CONCAT('update table2 set ''',#col_name ,''' = '';'' where time between ''',#starttime,''' and ''',#endtime,'''');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
CLOSE startendTime;
end;
SET i = i + 1;
END LOOP temp_hotelingloop;
CLOSE col_names;
end;
select * from table2;
DROP TABLE table2;
END
Any help please?
Thanks in advance
SET #sql = CONCAT('update table2 set ''',#col_name ,''' = '';'' where time between ''',#starttime,''' and ''',#endtime,'''');
You are using #col_name here, but on your declaration missing the #
declare col_name varchar(50);

Error Code: 1062 Duplicate entry for key 'PRIMARY'

I am constantly getting a Error code 1062: Duplicate Entry.
The first row insert, but then it fails on the same ID.
So everytime I hit execute it will increment: 1466, 1467, 1468, 1469.
And each time there is the same record entered, so I am assuming the autoincrement is only working for the first iteration.
Table:
'entity':
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL,
`enterprise_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1474 DEFAULT CHARSET=latin1 COMMENT=\'Comment'
Stored procedure:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `tp_to_entityPROC`()
DETERMINISTIC
COMMENT 'stored'
BEGIN
DECLARE done BOOLEAN DEFAULT 0;
DECLARE Tid INT;
DECLARE Tt_name TEXT;
DECLARE allt CURSOR FOR
SELECT training_provider_id, training_provider_name
FROM training_providers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN allt;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH allt INTO Tid, Tt_name;
SET #id = 0;
SET #t_name = 0;
SET #id = Tid;
SET #t_name = Tt_name;
SET #empty = '';
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);
SET #my_id = LAST_INSERT_ID();
IF #my_id != 0 THEN
UPDATE training_awarded_providers
SET training_awarded_provider_id = #my_id
WHERE training_awarded_provider_id = #id;
END IF;
END IF;
END LOOP;
CLOSE allt;
END
Not sure about the exact error of duplicate entry but your posted code is not going to work.
Your Table schema
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL <-- Here it's non null column
In your store procedure you are trying to insert null to reg_num column which will never succeed
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);

MySQL stored procedure anomaly: One line gets executed, another skipped?

I have a stored procedure, that checks if there is a user with the same e-mail address as the input, if not, then registeres one.
Here is the table:
CREATE TABLE IF NOT EXISTS `overkill`.`accounts` (
`accountID` INT NOT NULL AUTO_INCREMENT ,
`email` VARCHAR(64) NOT NULL ,
`firstName` VARCHAR(32) NOT NULL ,
`lastName` VARCHAR(32) NOT NULL ,
`passSaltedSHA` BINARY(20) NOT NULL ,
`salt` BINARY(20) NOT NULL ,
`gender` ENUM('m','f') NOT NULL ,
`birthDate` DATE NOT NULL ,
`regTime` TIMESTAMP NOT NULL ,
PRIMARY KEY (`accountID`) )
ENGINE = InnoDB;
Here is the stored procedure:
DELIMITER $$
CREATE PROCEDURE `overkill`.`registerUser` (
IN emailIN VARCHAR(64),
IN passwordIN VARCHAR(16),
IN firstNameIN VARCHAR(32),
IN lastNameIn VARCHAR(32),
IN birthIN DATE,
IN genderIN ENUM('f','m'))
BEGIN
DECLARE existingMailAccLOG INT DEFAULT NULL;
DECLARE saltLOC CHAR(40);
DECLARE regSuccessLOC BOOLEAN DEFAULT FALSE;
SELECT COUNT(*) INTO existingMailAccLOG FROM `overkill`.`accounts` WHERE `accounts`.`email` = emailIN;
IF existingMailAccLOG = 0 THEN
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
INSERT INTO `overkill`.`accounts` (`email`, `firstName`, `lastName`, `passSaltedSHA`, `salt`, `gender`, `birthDate`) VALUES(emailIN, firstNameIN, lastNameIn, UNHEX(SHA1(CONCAT(passwordIN, saltLOC))), UNHEX(saltLOC), genderIN, birthIN);
END IF;
SELECT regSuccessLOC AS `registered`, saltLOC AS `salt`;
END
If I call:
CALL registerUser("abc#def.com", "pass", "firstn", "lastn", "2012-01-01", "f");
It inserts a line into the accounts table, but forgets to return the proper values that I set inside the IF
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
How is it even possible? Why are theese lines skipped and INSERT still gets executed, without mistake?
Try to add "#" in front of your variable names after DECLARE keyword. It can cause some confusion, as it is described here: MySQL: #variable vs. variable. Whats the difference? (Part2) and here: MySQL: #variable vs. variable. Whats the difference?