below is my query:
DELIMITER $$
DROP PROCEDURE IF EXISTS `UpdateDB_Base_Url`$$
CREATE PROCEDURE UpdateDB_Base_Url()
BEGIN
DECLARE #rownum INT DEFAULT 1;
DECLARE #tbname VARCHAR(50);
WHILE #rownum<105 DO
SET #tbname= SELECT CONCAT((SELECT dbname FROM temp_db WHERE rownum=#rownum),'.','core_config_data');
UPDATE #tbname t
SET t.`value` =CONCAT(SUBSTRING(`value`, 1,LOCATE('.' ,`value`)),'magapa.ns-staging.com.au')
WHERE t.`value` LIKE '%staging-php%';
SET #rownum=#rownum+1;
END WHILE;
END$$
DELIMITER ;
temp_db table has db names with row number upto 104 records. here i am trying to update a table by going through all dbs in my server and i am getting following error
Query: CREATE PROCEDURE UpdateDB_Base_Url() begin declare #rownum int default 1; declare #tbname varchar(50); while #rownum<105 do SET ...
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 '#rownum int default 1;
declare #tbname varchar(50);
while #rownum<105 do
SET #' at line 3
Can someone help me with this?
Thanks!
There are few issues with your code.
You need not qualify local variables with '#' symbol. They are for
user/session variables.
You can read output of an expression into a local variable using
select ... into. No explicit set and select are required.
You can't just update a table with table name read from a
variable, directly. You have to use Prepared Statement.
Change your code as below:
DELIMITER $$
DROP PROCEDURE IF EXISTS `UpdateDB_Base_Url` $$
CREATE PROCEDURE UpdateDB_Base_Url()
BEGIN
DECLARE _rownum INT DEFAULT 1;
DECLARE _tbname VARCHAR(50);
SET _rownum := 1;
WHILE _rownum < 105 DO
SELECT CONCAT( dbname, ',', 'core_config_data' )
INTO _tbname
FROM temp_db
WHERE rownum = _rownum;
SET #sql := CONCAT( 'UPDATE ', _tbname, ' t ' );
SET #sql := CONCAT( #sql, ' SET t.`value` = ' );
SET #sql := CONCAT( #sql, ' CONCAT( SUBSTRING( t.`value`, 1, ' );
SET #sql := CONCAT( #sql, ' LOCATE( \'.\', t.`value` ) )' );
SET #sql := CONCAT( #sql, ', \'magapa.ns-staging.com.au\' )';
SET #sql := CONCAT( #sql, ' WHERE t.`value` LIKE \'%staging-php%\'' );
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
SET _rownum := _rownum + 1;
END WHILE;
END;
$$
DELIMITER ;
Related
My problem: I have a few tables in mysql database with column "URL". I want to extract all of URLs to text file or another table.
Is it good way to go?
DELIMITER $$
CREATE or replace PROCEDURE link()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE tablename varchar(1000) DEFAULT "";
DECLARE link_tables
CURSOR for
SELECT table_name FROM information_schema.columns WHERE table_name like '__baza%' and COLUMN_NAME like 'url';
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finished = 1;
OPEN link_tables;
getTable: LOOP
fetch link_tables into tablename;
IF finished = 1 THEN s
LEAVE getTable;
END IF;
select url from tablename into ... <<<< is it good idea? what to do next?
END LOOP getTable;
close link_tables;
END$$
DELIMITER ;
CALL link();
CREATE PROCEDURE link_urls (prefix VARCHAR(64))
BEGIN
SELECT GROUP_CONCAT( CONCAT( 'SELECT url FROM ', table_name) SEPARATOR ' UNION ')
INTO #sql
FROM information_schema.columns
WHERE table_name like CONCAT(prefix, '%');
SET #sql = CONCAT( 'CREATE TABLE urls ', #sql );
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
END
fiddle
I need to get the result table with there fields
- table_name, min_date, max_date
Here is my query, which I should execute for all tables
SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM testTable
GROUP BY short_date
HAVING COUNT(*) > 1) as Duplicates
Then I found out how to get all table names
I do it in this way
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
But I don't know how to execute it for all table and fill in the result in a new table.
I tried to do it in this way
DECLARE #DB_Name varchar(50)
DECLARE #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
But I got this error
Syntax error or access violation: 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 'DECLARE #DB_Name varchar(50) DECLARE
#Command varchar(100)' at line 1
UPD
CREATE PROCEDURE GetData()
BEGIN
DECLARE #DB_Name varchar(50), #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%_') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END;
CLOSE database_cursor
DEALLOCATE database_cursor
END;
CALL GetData()
Add DELIMITER $$ at the start; add DELIMITER ; after END.
Get rid of declaring Command. Instead use #command, which does not need to be declared.
Add SELECT #command; after the SELECT #command := ...; so that we can do some debugging.
The CLOSE and DEALLOCATE statements need ; to terminate them.
Test for running out of rows to FETCH.
You really need to look at a number of examples of Stored procedures, especially those with cursors.
Update
Ugh, I did not spot even half the syntax errors. This might work (I can't tell because I don't have your particular tables or columns.):
DROP PROCEDURE IF EXISTS so42856538;
DELIMITER $$
CREATE PROCEDURE so42856538()
LANGUAGE SQL
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE _TableName varchar(64);
DECLARE _done INT DEFAULT FALSE;
DECLARE database_cursor CURSOR FOR
SELECT TABLE_NAME
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA` = 'test'
AND `TABLE_NAME` LIKE 'test%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = TRUE;
OPEN database_cursor;
curs_loop: LOOP
FETCH NEXT FROM database_cursor INTO _TableName;
IF _done THEN LEAVE curs_loop; END IF;
SET #Command := CONCAT(
'SELECT MIN(short_date) as FirstDuplicatedDate,
MAX(short_date) as LastDuplicatedDate
FROM ( SELECT short_date, type, value, count(*) as cnt
FROM ', _TableName, '
WHERE type = "test"
GROUP BY short_date, type, value
HAVING COUNT(*) > 1 ) as Duplicates'
);
SELECT _TableName, #command; -- Debugging (remove if it is clutter)
PREPARE _sql FROM #command;
EXECUTE _sql;
DEALLOCATE PREPARE _sql;
END LOOP;
CLOSE database_cursor;
END $$
DELIMITER ;
CALL so42856538;
right... you might want to try this.
remove this line and run the query again.
DECLARE #DB_Name varchar(50), #Command varchar(100);
i think in mysql you can just use a variable without declaring it and then cast when necessary.
As far as my knowledge concern this error is due to ,DELIMETER and one more thing that you have to apply cursor properly to iterate whole rowset.Here in below code i had wrote down procedure with CURSOR.Make dynamic query and execute that dynamic query using
PREPARE stmt FROM #VAR_QRY; EXECUTE stmt;
That dynamic query will returns exact output you want.Here i had assuming that you have basic knowledge about trigger,loop and Cursor
Try below code.
Hope this will helps.
DROP PROCEDURE IF EXISTS ITERATEALLTABLE;
DELIMITER $$
CREATE PROCEDURE ITERATEALLTABLE()
BEGIN
DECLARE VAR_TABLE varchar(100);
DECLARE VAR_QRY varchar(100);
DECLARE VAR_FINISHED INT(11) DEFAULT 0;
DECLARE DATABASE_CURSOR CURSOR FOR
SELECT name AS TableNames
FROM (
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
)Z ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET VAR_FINISHED = 1;
OPEN DATABASE_CURSOR;
GET_NEXTRECORD: LOOP
FETCH DATABASE_CURSOR INTO VAR_TABLE;
IF VAR_FINISHED = 1 THEN
LEAVE GET_NEXTRECORD;
END IF;
SET #VAR_QRY = CONCAT("SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM " , VAR_TABLE , " WHERE type = 'test'
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates");
PREPARE stmt FROM #VAR_QRY;
EXECUTE stmt;
END LOOP GET_NEXTRECORD;
CLOSE DATABASE_CURSOR;
END;
CALL ITERATEALLTABLE;
I'm working with MySQL 5.6 and trying to a simple procedure seen below.
drop procedure if exists procsBook;
DELIMITER $$
CREATE PROCEDURE procsBook()
main:begin
DECLARE abc VARCHAR(256);
DECLARE def VARCHAR(256);
DECLARE field_name2 VARCHAR(256);
DECLARE field_names VARCHAR(256);
DECLARE bkid BIGINT(20);
SET abc:= NULL;
SET def:= NULL;
SET field_name2:= NULL;
SET field_names:= NULL;
SET bkid:= 0;
select a.field_name,b.column_name into abc,def from table1 a join table2 b where a.field_label=b.field_label and b.table_name='Table13' and b.section_name='English' group by a.field_name limit 1;
IF(abc is not null)
then
IF (SUBSTRING(abc,7,1)=1)
THEN
SELECT book1,bookId INTO field_names,bkid FROM shelf1 WHERE rowstate=0;
SET #vSelectQury = CONCAT('update shelf2 set def = ' , field_names, ' where book_id = ', bkid);
PREPARE vDynamicSSql FROM #vSelectQury;
EXECUTE vDynamicSSql;
DEALLOCATE PREPARE vDynamicSSql;
END IF;
END IF;
END $$
DELIMITER ;
Call:
call procsBook();
This is throwing the following error:
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 'where book_id = 22' at line 1
Any help please?
I think you need to add quotes around field_names.
SET #vSelectQury = CONCAT('update shelf2 set ', def, ' = \'' , field_names,
'\' where book_id = ', bkid); PREPARE vDynamicSSql FROM #vSelectQury;
(or if your setup is different you may need to change the escaping for ' character)
Updated you should not directly use def, but use the value of def in this case.
I have created the following MySQL SP successfully..
CREATE DEFINER=`root`#`%` PROCEDURE `Common_Proc_Create_NewId`
(
TableName VARCHAR(250),
ColumnName VARCHAR(150),
OUT ReturnId BIGINT
)
BEGIN
DECLARE varb BIGINT;
SET #NewId:= CONCAT('SELECT (IFNULL(MAX(', ColumnName, '), 0) + 1) INTO ', varb, ' FROM ', TableName);
PREPARE Stmnt FROM #NewId;
EXECUTE Stmnt;
DEALLOCATE PREPARE Stmnt;
SET ReturnId = varb;
END$$
But when this was called from another SP I got the following error:
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
Calling SP
CREATE DEFINER=`root`#`%` PROCEDURE `Masters_Proc_Create_BranchType`(
BranchTypName VARCHAR(100)
)
BEGIN
CALL Common_Proc_Create_NewId('Masters_BranchType', 'BranchTypeId', #Id);
INSERT INTO Masters_BranchType (BranchTypeId, BranchTypeName) VALUES (#Id, BranchTypName);
SELECT #Id;
END$$
In your stored procedure Common_Proc_Create_NewId the part into varb was causing the issue and think it's not allowed that way in a prepared statement (not sure though). Instead the way you are doing, try like below and it works fine (a sample code included)
delimiter //
CREATE PROCEDURE dynamic1(IN tbl VARCHAR(64), IN col VARCHAR(64), OUT ret int)
BEGIN
SET #s = CONCAT('SELECT #i := (IFNULL(MAX(', col, '), 0) + 1) FROM ', tbl);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
set ret = #i;
END
//
delimiter ;
call dynamic1('test1','col',#id);
select #id;
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