stored procedure stops working after first update - mysql

I have a task related to MYSQL where I am required to gather a particular set of values from a horizontal table and insert it into another table. The values in the table are like Index_0, AngleValue_0, Index_1, AngleValue_1,.....Index_11, AngleValue_11. I have to identify a set by the Index value, grab all the values of that set (for example if the Index is identified as Index_0, then grab Index_0 and AngleValue_0), and insert it into another table.
I have created a stored procedure for this, but it works for the first time and then stops updating.
Here is how my stored procedure looks.
DELIMITER //
drop procedure if exists updaterearseattorquereapir//
create procedure updaterearseattorquereapir(in ind int, in kanbn varchar(50), in rp_bdg int, in tl_bdg int, in qc_bdg int)
BEGIN
set #cnt = 0;
WHILE #cnt <= 11 DO
set #i = 0;
DROP TEMPORARY TABLE IF EXISTS indexcheck_Temp;
set #sql_check = CONCAT('CREATE TEMPORARY TABLE indexcheck_Temp
Select ',concat('Index_',#cnt),' as a From rearseattorque where ',concat('Index_',#cnt),'=', ind,' and Kanban = ',"#kanbn");
prepare stmt from #sql_check;
Execute stmt;
deallocate prepare stmt;
select #i := a from indexcheck_Temp;
if ind = #i
then
DROP TEMPORARY TABLE IF EXISTS rearseattorquerepair_Temp;
set #sql1 = CONCAT('
CREATE TEMPORARY TABLE rearseattorquerepair_Temp
SELECT Kanban, ',rp_bdg,', ',tl_bdg,', ',qc_bdg,', DTRowUpdate, ',concat('AngleValue_',#cnt),', ',concat('AngleStatus_',#cnt),', ',
concat('Index_',#cnt),', ',concat('Name_', #cnt),', ',concat('Operator_',#cnt),', ',concat('PSETNumber_',#cnt),', ',
concat('TighteningID_',#cnt),', ',concat('TighteningStatus_',#cnt),', ',concat('TimeStamp_',#cnt),', ',
concat('TorqueValue_',#cnt),', ',concat('TorqueStatus_',#cnt),
' FROM rearseattorque where ',concat('Index_',#cnt),'=', ind,' and Kanban = ',"#kanbn");
prepare stmt from #sql1;
EXECUTE stmt;
deallocate prepare stmt;
Insert into rearseattorquerepair(Kanban
,RepairOperatorBadge
, TeamLeaderBadge
, QCBadge
, DTRowUpdate
, Bolt_AngleValue
, Bolt_AngleStatus
, Bolt_Index
, Bolt_Name
, Bolt_Operator
, Bolt_PSETNumber
, Bolt_TighteningID
, Bolt_TighteningStatus
, Bolt_TimeStamp
, Bolt_TorqueValue
, Bolt_TorqueStatus
)
Select * from rearseattorquerepair_Temp;
else
select 'data not found';
END if;
SET #cnt = #cnt + 1;
END WHILE;
END//
DELIMITER ;

Related

How to create a create table statement in a loop in mysql

I want to create multiple tables with just one statement (query).
Loop
start
(
create table a
)
a =a +1
end loop
So say it has to create 100 tables labeled as TABLE1, TABLE2, ...
Try the following procedure.
DROP PROCEDURE IF EXISTS `createTableProcTest`;
delimiter //
CREATE PROCEDURE `createTableProcTest`()
BEGIN
DECLARE count INT Default 0;
simple_loop: LOOP
SET #a := count + 1;
SET #statement = CONCAT('Create table Table',#a,' ( name VARCHAR(70), age int );');
PREPARE stmt FROM #statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET count = count + 1;
IF count=100 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END//
In order to execute just do the following:
Call createTableProcTest();
By executing the above procedure 100 tables will be created having name table1,...,table100.
And the table structure would look like following:
N:B: Procedure execution might take several seconds. Don't be impatient.
You need give us more details but, I think is easier to call a stored procedure, inside the loop, to create the procedure.
You need to create a procedure to create the tables you need and call this procedure inside the loop.
Ex:
CREATE PROCEDURE SP_Create_Table(IN tableName VARCHAR(50)) BEGIN SET
#sql = CONCAT('CREATE TABLE ', tableName, '(column1 INT(11))');
PREPARE stmt FROM #sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END
Now, call the create table procedure inside the loop
DELIMITER // CREATE FUNCTION CalcIncome ( starting_value INT ) RETURNS
INT BEGIN
DECLARE income INT; SET income = 0; label1: WHILE income <=
50 DO
call SP_Create_Table(CONVERT(VARCHAR(50),starting_value)); END WHILE label1; RETURN income; END; // DELIMITER;

Getting unknown column id on stored procedure call

I have following stored procedure to reset auto increments for a table that gets many inserts and deletes.
DROP PROCEDURE IF EXISTS reset_autoincrement;
DELIMITER $$;
CREATE PROCEDURE reset_autoincrement(IN tableName VARCHAR(250))
BEGIN
SELECT #max := MAX(`id`) + 1 + concat(' FROM ', tableName );
set #alter_statement = concat('ALTER TABLE ', tableName ,' AUTO_INCREMENT = ', #max);
PREPARE stmt FROM #alter_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$;
and call it with
call reset_autoincrement('queueIn');
and get
23:18:25 call reset_autoincrement('queueIn') Error Code: 1054. Unknown column 'id' in 'field list' 0,042 sec
A little excerpt of the table's columns:
id bigint(19) UN AI PK
created_at timestamp
updated_at timestamp
I have two questions.
Obviously ... why do I get this error - the column clearly is there.
The id column gets incremented to a million within 6 hours, there are many insert/delete operations throughout the day. Is there an even better way to reset auto_increments in mysql?
Because you are trying to make it a dynamic query (the below line) and as it stands currently it's a mixture of dynamic and normal query.
SELECT #max := MAX(`id`) + 1 + concat(' FROM ', tableName );
You should make it a dynamic query fully
SET #sql = "SELECT MAX(`id`) + 1 FROM " + tableName;
You would need to hold the variable from first dynamic query and use it in ALTER statement. Something like below
DELIMITER $$;
CREATE PROCEDURE reset_autoincrement(IN tableName VARCHAR(250))
BEGIN
SET #var1 = 0;
SET #sql = "SELECT MAX(`id`) + 1 INTO #var1 FROM " + tableName;
PREPARE stmt FROM #sql;
EXECUTE stmt;
SET #ID = #var1;
set #alter_statement = concat('ALTER TABLE ', tableName ,' AUTO_INCREMENT = ', #ID);
PREPARE stmt FROM #alter_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END $$;

Logic condition to avoid duplicate entries in stored procedure

I have the following stored procedure . I'm trying to insert the users from the table usuaris, whose admin variable is equal to 1, into the table that the stored procedure creates with the name( nombre varchar(50)) that is passed as a parameter.
When the procedure is called, it duplicates the user 'mary' with id 4. I've tried a couple of ways to implement the logic condition in order to avoid the duplication, but still, I'm missing something and I can't get the desired result. In the code below, the logic condition before the insertion is the last thing I've tried. Any ideas?
Thanks.
CREATE DEFINER=`root`#`localhost` PROCEDURE `createNewtable`(nombre varchar(50))
BEGIN
/*variable declaration*/
declare centinela int ;
declare id1 int ;
declare nom1 varchar(50);
declare admin1 enum('0','1') ;
declare cadena varchar(100); /*string to concatenate table creation and insertion*/
/*cursor declaration*/
declare cursor1 cursor for select * from users.usuaris where admin = '1' ;
declare continue handler for not found set #centinela = 1 ;
/*create the table with the name that's passed as parameter*/
set #cadena=concat("create table ",nombre,
"(
id2 int not null primary key,
nom2 varchar(50),
admin2 enum ('0','1')
)" );
prepare stmt from #cadena ;
execute stmt ;
deallocate prepare stmt;
/* loop that fetches the data from the table usuaris and
inserts them into the newly created table. */
set #centinela = 0 ;
open cursor1 ;
bucle: loop
fetch cursor1 into id1,nom1,admin1 ;
if ( centinela = 1 ) then
leave bucle ;
end if ;
/*logic condition to avoid entry duplication */
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end loop bucle;
close cursor1;
END
Here is the single-table database of users :
create database if not exists `users` ;
use `users` ;
create table usuaris(
id int not null auto_increment primary key ,
nom varchar(50),
admin enum ('0','1')
);
insert into usuaris(id,nom,admin)
values
(1,'jose','1'),
(2,'maria','0'),
(3,'frank','1'),
(4,'mary','1'),
(5,'godfrey','0') ;
Also it has to duplicate jose. The reason of duplication - if the IF statement isn't TRUE then you don't set the new #cadena variable BUT anyway execute PREVIOUS #cadena statement. You should move execution into the IF statement also:
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;
Also in SQL you should always try to avoid loops if it possible and use SQL statements instead.
You can replace your loop with one SQL statement:
INSERET INTO NEW_TABLE_NAME_HERE
SELECT id1,nom1,admin1
FROM users.usuaris where admin<>'1'
Further more you can use SELECT INTO statement syntax to automatically create new table without CREATE TABLE statement:
SELECT id1 as id2,
nom1 as nom2,
admin1 as admin2
INTO NEW_TABLE_NAME_HERE
FROM users.usuaris where admin<>'1'
Change ur below code to my new code and try-
Existing Code
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
New Code-
SET #cnt=SELECT count(*) FROM users.usuaris WHERE admin='1' AND id=#id1
IF #cnt>0 THEN
SET #cadena=CONCAT("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;

Dynamic query in procedure, how do I get OUT value?

I want to call a dynamic procedure with a particular time_stamp and pro_id.
In the first step I want to find out if that particular pro_id exists in the table. Is there anything wrong in the Concat statement? I do not get the desired OUT value
DELIMITER ;;
CREATE PROCEDURE 'ADDCONSENSUS'(IN time_stamp int(10), IN pro_id INT(10), OUT cnt INT(11))
BEGIN
SET #sql1 = CONCAT('SELECT COUNT(pid) INTO #cnt FROM ',time_stamp,' WHERE pid = ,pro_id);
PREPARE stmt from #sql1;
EXECUTE stmt;
END
You can try the following:
DELIMITER $$
DROP PROCEDURE IF EXISTS `ADDCONSENSUS`$$
CREATE PROCEDURE `ADDCONSENSUS`(
IN `time_stamp` INT,
IN `pro_id` INT,
OUT `cnt` INT)
BEGIN
SET #sql1 := CONCAT('
SELECT COUNT(`pid`) INTO #`cnt`
FROM `', CAST(`time_stamp` AS CHAR), '`
WHERE `pid` = ', CAST(`pro_id` AS CHAR));
PREPARE stmt FROM #sql1;
EXECUTE stmt;
SET `cnt` := #`cnt`;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
CALL `ADDCONSENSUS`(1395395302, 3, #`_count`);
SQL Fiddle demo

MySql, split a string and insert into table

I have two inputs for my stored procedure. One is the 'RoledID' and second one is the 'MenuIDs'. 'MenusIDs' is a list of comma separated menus ids that need to be inserted with RoledID. RoleId is just an INT and we need to put this RoledID against each MenuID. My table 'RolesMenus' contains two columns one for MenuID and one for RoleID.
Now I need to split MenuIDs and insert each MenuID with RoleID.
How can I write a stored procedure for it?
You can build one INSERT query (because statement allows to insert multiple records) and run it with prepared statements, e.g. -
SET #MenuIDs = '1,2,3';
SET #RoledID = 100;
SET #values = REPLACE(#MenuIDs, ',', CONCAT(', ', #RoledID, '),('));
SET #values = CONCAT('(', #values, ', ', #RoledID, ')'); -- This produces a string like this -> (1, 100),(2, 100),(3, 100)
SET #insert = CONCAT('INSERT INTO RolesMenus VALUES', #values); -- Build INSERT statement like this -> INSERT INTO RolesMenus VALUES(1, 100),(2, 100),(3, 100)
-- Execute INSERT statement
PREPARE stmt FROM #insert;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
As you see, it can be done without stored procedure.
Give this a go. It may need some tweaking if the MenuIDs string does not conform to 'menuId,menuId,menuId'.
Also I do not know what data type the menuId column is in your target table (INT?) so you may have to put some numeric checking in too (in case '1,2,3,banana,4,5' is passed in as the MenuIds input parameter).
DELIMITER $$
DROP PROCEDURE IF EXISTS `insert_role_menuids`$$
CREATE PROCEDURE `insert_role_menuids`(IN RoleID INT,IN MenuIDs varchar(500))
BEGIN
declare idx,prev_idx int;
declare v_id varchar(10);
set idx := locate(',',MenuIDs,1);
set prev_idx := 1;
WHILE idx > 0 DO
set v_id := substr(MenuIDs,prev_idx,idx-prev_idx);
insert into RolesMenus (RoleId,MenuId) values (RoleID,v_id);
set prev_idx := idx+1;
set idx := locate(',',MenuIDs,prev_idx);
END WHILE;
set v_id := substr(MenuIDs,prev_idx);
insert into RolesMenus (RoleId,MenuId) values (RoleID,v_id);
END$$
DELIMITER ;
for this solution, you must create a table with the name split_table, it can have a id(autoincrement) if you need it and must have a column where to store the value (I call it valor)
DELIMITER $$
USE `dbaname`$$
DROP PROCEDURE IF EXISTS `Split`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `Split`(
IN cadena VARCHAR(8000),
IN delimitador VARCHAR(10)
)
BEGIN
TRUNCATE split_table;
SET #posicion = 1;
SET #ldel = LENGTH(delimitador);
SET #valor = SUBSTRING_INDEX(cadena, delimitador, 1);
WHILE #valor <> '' AND #posicion > 0 DO
SET #valor = SUBSTRING_INDEX(cadena, delimitador, 1);
INSERT INTO split_table(valor) VALUES (#valor);
SET #posicion = POSITION(delimitador IN cadena);
SET #largo = LENGTH(cadena);
IF #largo >= #posicion THEN
SET cadena = SUBSTR(cadena, #posicion + #ldel, #largo - #posicion);
SET #valor = SUBSTRING_INDEX(cadena, delimitador, 1);
ELSE
SET #posicion = 0;
END IF;
END WHILE;
END$$
DELIMITER ;
First create procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `split_str_save_to_tmp_table`(
IN _str TEXT,
IN _table_name VARCHAR(80)
)
BEGIN
#DROP FIRST OLD TABLE
SET #q = CONCAT('DROP TEMPORARY TABLE IF EXISTS ', _table_name);
PREPARE st FROM #q;
EXECUTE st;
#CREATE TABLE
SET #q = CONCAT('CREATE TEMPORARY TABLE ', _table_name, '(id INT UNSIGNED NOT NULL PRIMARY KEY (id) )' );
PREPARE st FROM #q;
EXECUTE st;
SET #ids = REPLACE(_str, ',', '),(');
SET #ids = CONCAT('(', #ids, ')');
#INSERT INTO TABLE
SET #q = CONCAT('INSERT INTO ' , _table_name ,' VALUES');
SET #q = CONCAT(#q, #ids);
PREPARE st FROM #q;
EXECUTE st;
DEALLOCATE PREPARE st;
END
Then call
call split_str_save_to_tmp_table('1,2,3,4,5', 'tmp_split_product');
SELECT * FROM tmp_split_product
AFAIK MySQL does not have a function to split strings. Here is the MySQL manual for string related functions. In the comments section should be some information about workarounds for splitting string with substring-functions but not really usable:
MySQL manual