I have to following procedure trying to dynamically create a view.
CREATE DEFINER=`root`#`%` PROCEDURE `uspCreateViewFromTable`(IN ViewName varchar(255), IN TableName varchar(255))
BEGIN
#View Droppen falls sie schon erstellt wurde
SET #s = CONCAT('DROP VIEW IF EXISTS ',ViewName);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
# Verwendete Spalten filtern und Statement bauen
#SET #columns = CAST('SELECT ' AS VARCHAR(10));
DECLARE column varchar(500);
DECLARE column_cursor FOR SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = Tablename;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN column_cursor
read_loop: LOOP
FETCH column_cursor INTO column
# do something
SELECT column;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE column_cursor;
END
I get the Error "Missing END" and I have no idea why.
The syntax checker underlines the semikolon at the end of Line
DEALLOCATE PREPARE stmt;
When I move the dealloc to the end the syntac checker highlightes the semikolon at the line before.
EXECUTE stmt;
If I remove everthing after the dealloc it works.
Some problems:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements. See 13.6.3 DECLARE Syntax.
ERROR 1193 (HY000): Unknown system variable 'done'.
Check the syntax of cursors. See 13.6.6.2 Cursor DECLARE Syntax.
column is keyword and reserved word. See 9.3 Keywords and Reserved Words.
Missing some ;.
DELIMITER //
CREATE PROCEDURE `uspCreateViewFromTable`(
IN ViewName varchar(255),
IN TableName varchar(255)
)
BEGIN
/*
#View Droppen falls sie schon erstellt wurde
SET #s = CONCAT('DROP VIEW IF EXISTS ',ViewName);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
*/
# Verwendete Spalten filtern und Statement bauen
#SET #columns = CAST('SELECT ' AS VARCHAR(10));
-- DECLARE column varchar(500);
DECLARE `column` varchar(500);
DECLARE done BOOL DEFAULT FALSE;
/*
DECLARE column_cursor FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = Tablename;
*/
DECLARE column_cursor CURSOR FOR
SELECT column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = Tablename;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
#View Droppen falls sie schon erstellt wurde
SET #s = CONCAT('DROP VIEW IF EXISTS ',ViewName);
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- OPEN column_cursor
OPEN column_cursor;
read_loop: LOOP
-- FETCH column_cursor INTO column
FETCH column_cursor INTO `column`;
# do something
-- SELECT column;
SELECT `column`;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE column_cursor;
END//
DELIMITER ;
Related
following code is running fine, what I need to ask how can I use a variable instead of a table name written in cursor select statement?
block5: begin
declare var1 int default 0;
DECLARE done TINYINT DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR SELECT co_srno FROM vu_company where katscode in ('OGDC', 'LUCK', 'MCB');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cursor1;
my_loop: LOOP
FETCH cursor1 INTO var1;
IF done THEN
LEAVE my_loop;
ELSE
set #s = concat("insert into ", #temp_table_name_scrnr_data, " (sr_no) values (", var1, ")");
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END LOOP;
end block5;
I have a server with multiple schemas. I need to find specyfic email address. Every schema looks pretty much te same, they have same structure. What i wanted to do is to write a script to for displaying dbname and specyfic data related to given email . Heres my script, but it do not work:(
DELIMITER $$
#Drop procedure if exists SearchAllDb $$
Create procedure SearchAllDb()
BEGIN
DECLARE DB_NAME Varchar(50);
DECLARE done INT default FALSE;
DECLARE CURSOR_ALL_DB_NAMES CURSOR FOR
SELECT schema_name from information_schema.schemata
WHERE schema_name like 'itools_%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN CURSOR_ALL_DB_NAMES;
myloop: LOOP
FETCH CURSOR_ALL_DB_NAMES INTO DB_NAME;
IF done THEN LEAVE myloop;
END IF;
WHILE done != TRUE DO
SET #SQL = CONCAT('select DB_NAME, id, sn, name, email
from',DB_NAME,'.`open_cases` where email like 'xxx#yahoo.com'');
prepare stmt from #SQL;
execute stmt;
deallocate prepare stmt;
END WHILE;
CLOSE CURSOR_ALL_DB_NAMES;
END;
DELIMITER ;
I have something similar written in t-sql and it works...
DECLARE #DB_NAME VARCHAR(50);
DECLARE CURSOR_ALL_DB_NAMES CURSOR FOR
SELECT name FROM master.sys.databases
WHERE name like 'pickup-%' and name!= 'pickup-stored';
OPEN CURSOR_ALL_DB_NAMES;
FETCH NEXT FROM CURSOR_ALL_DB_NAMES INTO #DB_NAME
WHILE ##Fetch_Status = 0
BEGIN
Print #DB_NAME;
exec ('select '''+ #DB_NAME + ''' as db, id, sn, email from ['+
#DB_NAME+'].dbo.requests where email in (''xxx#live.com'')');
FETCH NEXT FROM CURSOR_ALL_DB_NAMES INTO #DB_NAME
END
CLOSE CURSOR_ALL_DB_NAMES;
DEALLOCATE CURSOR_ALL_DB_NAMES;
Looks like you were doing fine up until you introduced the WHILE.
THE WHILE is redundant since you are using a LOOP, you should remove those lines.
The LOOP doesn't have an END.
The CONCAT statement will treat the first use of DB_NAME as one of your column names and there are some quoting issues with the LIKE.
The ';' at the end of the procedure should be '$$' which you have specified as your DELIMITER.
I've taken a few liberties with your variable names but this tidied up version should illustrate the points.
DELIMITER $$
DROP PROCEDURE IF EXISTS SearchAllDb $$
CREATE PROCEDURE SearchAllDb()
BEGIN
DECLARE db_name VARCHAR(64);
DECLARE done INT DEFAULT FALSE;
DECLARE cur CURSOR FOR
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name LIKE 'itools_%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
myloop: LOOP
FETCH cur INTO db_name;
IF done THEN
LEAVE myloop;
END IF;
SET #SQL = CONCAT('SELECT ''', db_name, ''', id, sn, name, email
FROM `', db_name,'`.`open_cases`
WHERE email LIKE ''xxx#yahoo.com''');
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
There's a very good CURSOR example in the documentation at https://dev.mysql.com/doc/refman/5.7/en/cursors.html which will help you with the structure of the procedure.
I´ve been trying to create a stored procedure that will copy my database to another database. The problem is that only the first table is copying. Do you guys see any errors in the code?
DELIMITER $$
DROP PROCEDURE IF EXISTS fes_backup $$
CREATE PROCEDURE do_backup (IN name_bbdd VARCHAR(20), IN new_name_bbdd VARCHAR(20))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE name_table VARCHAR(20);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables
WHERE table_schema=name_bbdd AND table_type="base table";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN cur1;
bucle: LOOP
FETCH cur1 INTO name_table;
IF done=1 THEN
LEAVE bucle;
END IF;
SELECT CONCAT("Copio ",name_table," a nova base de dades ",new_name_bbdd);
SET #aux = CONCAT("CREATE TABLE ",name_table," LIKE ", name_bbdd, ".", name_table);
PREPARE stmt1 FROM #aux;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET #aux = CONCAT("INSERT INTO ",name_table," SELECT * FROM ", name_bbdd, ".", name_table);
PREPARE stmt1 FROM #aux;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END LOOP bucle;
CLOSE cur1;
END$$
DELIMITER ;
Thanks a lot!
How can I use values returned from Cursor as table names in mysql procedures ?
DECLARE cur CURSOR FOR
select table_name, column_name
from information_schema.columns
where table_schema = 'foo' and table_name like 'bar%';
OPEN cur;
loop1: LOOP
FETCH cur
INTO table_val, column_val;
IF no_more_rows THEN
CLOSE cur;
LEAVE loop1;
END IF;
update table_val SET column_val ...
This throws error that foo.table_val doesnt exist. How can I get the actual table name to be passed to the select statement ?
Change update table_val SET column_val ... into
SET #sql = CONCAT('UPDATE ', table_val, ' SET ', column_val, ' = whatever WHERE...');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Read more about it here.
But note that you can not parameterize table and column names. This only works with values.
I will also share my fix. hope it will help someone too.
-- set to "$$" as we have ";" inside of Procedure. MySQL will be confused.(is this part of Procedure or should I run it now?)
DELIMITER $$
CREATE PROCEDURE UpdateTable()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE _table_name CHAR(255);
DECLARE cur CURSOR FOR
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'db_name' AND table_type = "BASE TABLE";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
My_loop: LOOP
FETCH cur INTO _table_name;
SET #my_table_name = _table_name;
IF done THEN
LEAVE My_loop;
END IF;
SET FOREIGN_KEY_CHECKS = 0;
SET #stmt = CONCAT('ALTER TABLE ', #my_table_name, ' CONVERT TO CHARACTER SET utf8;');
PREPARE stmt1 FROM #stmt;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
SET FOREIGN_KEY_CHECKS = 1;
END LOOP;
CLOSE cur;
END$$
-- set to normal. ";"
DELIMITER ;
I want the procedure to take parameter answertable and partid in the select statement,
but when i call it it doesn't replace the parameter answertable with the value
the call call updateTotalScores('quiz_participation', 'quiz_answer', 1)
returns the error: 1146 - Table 'quizdb.answertable' doesn't exist
passing the id works, but passing the table name doesn't
so how do i pass the table name to the select in
DECLARE cur1 CURSOR FOR SELECT SUM(`score`), SUM(`maxscore`) FROM answertable WHERE `idParticipation`=partid;
entire procedure:
DELIMITER $$
CREATE PROCEDURE updateTotalScores(IN participationtable CHAR(64), IN answertable CHAR(64), IN partid INT)
BEGIN
DECLARE done INTEGER DEFAULT 0;
DECLARE sscore INTEGER DEFAULT 0;
DECLARE smaxscore INTEGER DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT SUM(`score`), SUM(`maxscore`) FROM answertable WHERE `idParticipation`=partid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO sscore, smaxscore;
UNTIL done = 1
END REPEAT;
CLOSE cur1;
UPDATE participationtable SET `score`=sscore, `maxscore`=smaxscore WHERE `idParticipation`=partid;
END $$
DELIMITER ;
For completeness
the table name cannot be passed to a MySql cursor, at least not yet
http://forge.mysql.com/worklog/task.php?id=3433
the answer from below (corrected a bit)
DELIMITER $$
CREATE PROCEDURE updateTotalScores(IN participation_table VARCHAR(45), IN answer_table VARCHAR(45), IN part_id INT)
BEGIN
SET #stmt_text=CONCAT("SELECT #score := SUM(`score`), #maxscore := SUM(`maxscore`) FROM ",
answer_table, " WHERE `idParticipation`=", part_id);
PREPARE stmt FROM #stmt_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #stmt_text=CONCAT("UPDATE ", participation_table,
" SET `score`=?, `maxscore`=? WHERE `idParticipation`=", part_id);
PREPARE stmt FROM #stmt_text;
EXECUTE stmt USING #score, #maxscore;
DEALLOCATE PREPARE stmt;
END $$
I believe you cannot do it in this manner.
In order to achieve this, you should use Dynamic SQL.
Note that you cannot open a cursor using Dynamic SQL either. But in your case, there seems to be no need for a cursor.
If i understand your code correctly, you can just use user variables and probably achieve what you are trying to do using 2 Dynamically prepared statements.
SET #stmt_text=CONCAT("SELECT #score = SUM(`score`), #maxscore=SUM(`maxscore`) FROM ",
answertable, "WHERE `idParticipation`= ", partid);
PREPARE stmt FROM #stmt_text;
EXECUTE stmt USING #a;
And then you update the values using the below statement
SET #stmt_text=CONCAT("UPDATE", participationtable, " SET `score`=#score,
`maxscore`=#maxscore WHERE `idParticipation`=", partid);
PREPARE stmt FROM #stmt_text;
EXECUTE stmt USING #a;
DEALLOCATE PREPARE stmt;
Note: Please check the syntax. I cannot test it to verify it exactly but i hope you get the idea.