I wanted to replace a value (1 > -1) in a table with the following commands
UPDATE table_name
SET column_name = replace(column_name, '1', '-1');
However,I decided to learn how to use stored programs in Mysql, since the number of columns are large with their regularly formatted namesn ('i01', 'i02',...).
Below is my trial:
DELIMITER $$
DROP PROCEDURE IF EXISTS example$$
CREATE PROCEDURE example()
BEGIN
DECLARE p INT;
DECLARE str VARCHAR(20);
SET p = 1;
WHILE p < 100 DO
IF p <= 9 THEN SET str = CONCAT('i0', p);
ELSE SET str = CONCAT('i', p);
END IF;
UPDATE target_table
SET `str` = replace(str, '1', '-1');
SET p = p + 1;
END WHILE;
END$$
When I source the script, which was OK and call the function, there says ERROR 1054 (42S22): Unknown column 'str' in 'field list.'
How can I pass the variable, in this case #str, inside UPDATE query?
I searched online and found PREPARE could be an answer but could not figure out how to use that in my case.
Yes, you were on the right track with PREPARE.. the only issue is you have to concate the query string with the variable name outside of the string to access its contents.
SET #A = (SELECT CONCAT("UPDATE target_table SET `", #str, "` = replace(str, '1', '-1');"));
PREPARE qry FROM #A;
EXECUTE qry;
DEALLOCATE PREPARE qry;
if the replace you have is related to your variable #str (because you dont have the # sign there I'm not sure if its an actual column or the variable) then you need to change #A a little bit
SET #A = (SELECT CONCAT("UPDATE target_table SET `", #str, "` = replace(", #str, ", '1', '-1');"));
DEMO
with your DECLAREs this should be your final query
DELIMITER $$
DROP PROCEDURE IF EXISTS example$$
CREATE PROCEDURE example()
BEGIN
DECLARE p INT;
DECLARE str VARCHAR(20);
DECLARE update_qry VARCHAR(200);
SET p = 1;
WHILE p < 100 DO
-- set up column name
IF p <= 9
THEN SET str = CONCAT('i0', p);
ELSE SET str = CONCAT('i', p);
END IF;
-- set up query to execute
SET update_qry = CONCAT("UPDATE target_table SET `", str, "` = replace(", str, ", '1', '-1');")
-- prepare execute and deallocate query
PREPARE qry FROM update_qry;
EXECUTE qry;
DEALLOCATE PREPARE qry;
-- increment counter for next column name
SET p = p + 1;
END WHILE;
END$$
Related
I have create a trigger which is create a dynamic query.and execute it i had tried 'EXECU q' but it does not work. how can i run/execute that dynamic query.
BEGIN
DECLARE a INT Default 0 ;
DECLARE str VARCHAR(255);
DECLARE q VARCHAR(500);
SET q = 'insert into '+new.master_name+' values(';
simple_loop: LOOP
SET a=a+1;
SET str = SPLIT_STRING(new.remarks,"|",a);
SET q = CONCAT(q,str+',');
SET q = LEFT(q, LENGTH(q) - 1);
IF str='' THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
SET q = CONCATE(q,');');
EXEC q
END
This is Trigerr
this is Function which i made
RETURN REPLACE(
SUBSTRING(
SUBSTRING_INDEX(str , delim , pos) ,
CHAR_LENGTH(
SUBSTRING_INDEX(str , delim , pos - 1)
) + 1
) ,
delim ,
''
)
I've written a stored procedure to execute dynamically constructed sql statements.
Usage
SET #index := 7;
CALL eval(CONCAT('SELECT ', #index));
Implementation
DELIMITER $$
CREATE PROCEDURE eval(IN dynamic_statement TEXT)
BEGIN
SET #dynamic_statement := dynamic_statement;
PREPARE prepared_statement FROM #dynamic_statement;
EXECUTE prepared_statement;
DEALLOCATE PREPARE prepared_statement;
END$$
DELIMITER ;
From my understanding you must make a prepared statement from your string first in order to execute it. So the following partial code should work in replacement for just EXEC q:
PREPARE thequery FROM q;
EXECUTE thequery;
use prepare statement to execute your dynamic query
BEGIN
DECLARE a INT Default 0 ;
DECLARE str VARCHAR(255);
DECLARE q VARCHAR(500);
DECLARE q1 VARCHAR(500);
DECLARE q2 VARCHAR(500);
SET #q = 'insert into '+new.master_name+' values(';
simple_loop: LOOP
SET a=a+1;
SET str = SPLIT_STRING(new.remarks,"|",a);
SET q = CONCAT(#q,str+',');
SET q1 = LEFT(q, LENGTH(q) - 1);
IF str='' THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
SET q2 = CONCATE(q1,');');
PREPARE stmt FROM q2;
EXECecute stmt;
deallocate PREPARE stmt;
END
I wanted to build around 900 views(1 view for 1 table and based on 2 conditions) and i have all the table names in a table in mysql environment. I have created a stored proc . For test purpose i used limit 1.
I get below error when i call the sp.
Actually I re-wrote a mssql sp, did i miss anything here. please help
CALL ca_uim.sp_viewcreation_ontime() Error Code: 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 'NULL' at line 1 0.000 sec
USE `ca_uim`;
DROP procedure IF EXISTS `sp_viewcreation_ontime`;
DELIMITER $$
USE `ca_uim`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_viewcreation_ontime`()
BEGIN
DECLARE qos varchar(255);
DECLARE pos int;
DECLARE r_table varchar(255);
DECLARE view varchar(255);
DECLARE cview varchar(2048);
DECLARE done int default 0;
DECLARE qos_cursor CURSOR FOR SELECT DISTINCT qos,r_table FROM S_QOS_DATA ORDER BY 2 limit 1;
DECLARE continue handler for not found set done = 1;
OPEN qos_cursor;
-- Perform the first fetch.
FETCH qos_cursor INTO qos, r_table;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE not done
DO
-- Check QOS name for '-' character & replace with '_' if exist
SET pos = LOCATE('-',qos, 1);
IF pos != 0
THEN
SET qos = INSERT(qos, pos, 1, '_');
END IF;
-- Check QOS name for '/' character & replace with '_' if exist
SET pos = LOCATE('/',qos, 1);
IF pos != 0
THEN
SET qos = INSERT(qos, pos, 1, '_');
END IF;
-- Check QOS name for '(' character & replace with '_' if exist
SET pos = LOCATE('(',qos, 1);
IF pos != 0
THEN
SET qos = INSERT(qos, pos, 1, '_');
END IF;
-- Check QOS name for ')' character & replace with '_' if exist
SET pos = LOCATE(')',qos, 1);
IF pos != 0
THEN
SET qos = INSERT(qos, pos, 1, '_');
END IF;
-- Create view
SET view = CONCAT('V_',qos);
SET cview = CONCAT('CREATE VIEW ',view,' AS ',
'SELECT Q.source,Q.target,Q.origin,Q.robot,Q.probe,D.sampletime,D.samplevalue,D.samplestdev,D.samplerate,D.tz_offset ',
'FROM S_QOS_DATA Q JOIN ',r_table,' D ON Q.table_id=D.table_id');
BEGIN
-- Suppress Error message for Views that don't exist
DECLARE CONTINUE HANDLER FOR 1051
set #stmt_str = CONCAT('DROP VIEW ',view);
prepare stmt from #stmt_str;
execute stmt;
deallocate prepare stmt;
END;
BEGIN
-- Create the View, Catch tables that don't have samplestdev & samplerate fields
DECLARE CONTINUE HANDLER FOR 1054
set #stmt_str = cview;
prepare stmt from #stmt_str;
execute stmt;
deallocate prepare stmt;
/* PRINT CONCAT('Created View: ' , view) */
END;
BEGIN
DECLARE CONTINUE HANDLER FOR 1054
SET cview = CONCAT('CREATE VIEW ',view,' AS ',
'SELECT Q.source,Q.target,Q.origin,Q.robot,Q.probe,D.sampletime,D.samplevalue,D.tz_offset ',
'FROM S_QOS_DATA Q JOIN ',r_table,' D ON Q.table_id=D.table_id');
set #stmt_str = cview;
prepare stmt from #stmt_str;
execute stmt;
deallocate prepare stmt;
/* PRINT CONCAT('Created View: ' , view) */
END;
-- PRINT 'qos: ' + #qos + ' ' + #r_table+' '+#view
-- PRINT #cview
-- This is executed as long as the previous fetch succeeds.
FETCH qos_cursor INTO qos, r_table;
END WHILE;
CLOSE qos_cursor;
END$$
DELIMITER ;
Thanks
I have create a trigger which is create a dynamic query.and execute it i had tried 'EXECU q' but it does not work. how can i run/execute that dynamic query.
BEGIN
DECLARE a INT Default 0 ;
DECLARE str VARCHAR(255);
DECLARE q VARCHAR(500);
SET q = 'insert into '+new.master_name+' values(';
simple_loop: LOOP
SET a=a+1;
SET str = SPLIT_STRING(new.remarks,"|",a);
SET q = CONCAT(q,str+',');
SET q = LEFT(q, LENGTH(q) - 1);
IF str='' THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
SET q = CONCATE(q,');');
EXEC q
END
This is Trigerr
this is Function which i made
RETURN REPLACE(
SUBSTRING(
SUBSTRING_INDEX(str , delim , pos) ,
CHAR_LENGTH(
SUBSTRING_INDEX(str , delim , pos - 1)
) + 1
) ,
delim ,
''
)
I've written a stored procedure to execute dynamically constructed sql statements.
Usage
SET #index := 7;
CALL eval(CONCAT('SELECT ', #index));
Implementation
DELIMITER $$
CREATE PROCEDURE eval(IN dynamic_statement TEXT)
BEGIN
SET #dynamic_statement := dynamic_statement;
PREPARE prepared_statement FROM #dynamic_statement;
EXECUTE prepared_statement;
DEALLOCATE PREPARE prepared_statement;
END$$
DELIMITER ;
From my understanding you must make a prepared statement from your string first in order to execute it. So the following partial code should work in replacement for just EXEC q:
PREPARE thequery FROM q;
EXECUTE thequery;
use prepare statement to execute your dynamic query
BEGIN
DECLARE a INT Default 0 ;
DECLARE str VARCHAR(255);
DECLARE q VARCHAR(500);
DECLARE q1 VARCHAR(500);
DECLARE q2 VARCHAR(500);
SET #q = 'insert into '+new.master_name+' values(';
simple_loop: LOOP
SET a=a+1;
SET str = SPLIT_STRING(new.remarks,"|",a);
SET q = CONCAT(#q,str+',');
SET q1 = LEFT(q, LENGTH(q) - 1);
IF str='' THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
SET q2 = CONCATE(q1,');');
PREPARE stmt FROM q2;
EXECecute stmt;
deallocate PREPARE stmt;
END
I have mysql DB with incremental table names (ie. table1, table2, table3, tablen). Somewhere along the way this incrementation has skipped a few and there are gaps. I want to execute a script which will create the table with the correct table name when the loop finds a missing table. So something like..
for i=1 to 100
create table if not exists 'tablei'
***TABLE FIELD DECLARATIONS***
end
Any help much appreciated.
Something like (might need a few MySql syntax twiddles)
Declare #loopvar int
Declare #sql VarChar(8000)
Declare #table_definition VarChar(8000)
Set #table_definition = '(SomeField int null)'
Set #loopvar = 1
While #loopVar < 100
begin
set #sql = 'Create Table if not exists TableName' + Convert(VarChar(3),#loopvar) + #table_definition
exec(#sql)
set #loopvar = #loopvar + 1
end
should do it.
an answer with all the "MySql syntax twiddles":
DELIMITER //
CREATE PROCEDURE missing_tables(n INT)
BEGIN
WHILE n > 0
DO
SET #sql = CONCAT('create table if not exists table', n, ' (value INT)');
PREPARE cmd FROM #sql;
EXECUTE cmd;
DEALLOCATE PREPARE cmd;
SET n = n - 1;
END WHILE;
END; //
DELIMITER ;
CALL missing_tables(5);
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