I can't drop a table from a procedure.
This is the procedure in which it gives me the error.
CREATE PROCEDURE `procDropAllTables`()
BEGIN
DECLARE table_name VARCHAR(255);
DECLARE end_of_tables INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = DATABASE() AND t.table_type='BASE TABLE';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_of_tables = 1;
SET FOREIGN_KEY_CHECKS = 0;
OPEN cur;
tables_loop: LOOP
FETCH cur INTO table_name;
IF end_of_tables = 2 THEN
LEAVE tables_loop;
END IF;
SET #s = CONCAT('DROP TABLE IF EXISTS ' , table_name);
PREPARE stmt FROM #s;
EXECUTE stmt;
END LOOP;
CLOSE cur;
SET FOREIGN_KEY_CHECKS = 1;
END
I can drop drop tables if I do it manualy, so it isnt a user privileges problem
Related
I want to make an event that every 5 seconds create a backup of my tables in a tables_old.
I would also like to know how I can check if a table has not been modified and not make that copy.
This is my code:
create event ejer5
on schedule every 5 second
do
begin
DECLARE done INT DEFAULT FALSE;
DECLARE table_name varchar(30);
DECLARE cursor1 CURSOR FOR select table_name
from information_schema.tables
where table_type = 'BASE TABLE'
and table_schema not in ('information_schema', 'sys',
'performance_schema','mysql')
and table_schema = "world"
order by update_time desc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
open cursor1;
bucle:loop
fetch cursor1 into table_name;
IF done THEN
LEAVE bucle;
END IF;
SET #c = CONCAT('CREATE TABLE `',table_name,'_old', '` LIKE `',table_name,'`');
PREPARE stmt from #c;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end loop;
close cursor1;
end //
I have 2 schemas with exactly the same tables schema_oltp and schema_olap. I want to delete from selected tables in schema_oltp only the data which already exists in schema_olap. The tables I want to delete from are listed in a table called archived_to_delete. For each of the tables listed in archived_to_delete, I need to delete the data in batches of 100 000. This is what I have so far. It only deletes 100 000 in each table and stops. I want it to continue until there is no data in schema_oltp which also exists in schema_olap:
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `schema_oltp`.`schemaDeletes`(IN from_schema VARCHAR(100), IN to_schema VARCHAR(100))
BEGIN
DECLARE v_tname varchar(100);
DECLARE v_pkey varchar(455);
DECLARE v_upfield varchar(455);
DECLARE done INT DEFAULT 0;
DECLARE v_limit INT DEFAULT 100000;
DECLARE v_deleted INT;
DECLARE table_cursor CURSOR FOR SELECT a.table_name, a.column_name
FROM INFORMATION_SCHEMA.COLUMNS a
INNER JOIN archived_to_delete b
ON a.table_name = b.table_name
WHERE TABLE_SCHEMA = 'schema_oltp'
AND COLUMN_KEY='PRI'
ORDER BY b.archived_to_delete_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN table_cursor;
REPEAT
FETCH table_cursor INTO v_tname, v_pkey;
IF NOT done THEN
SET v_deleted=0;
SET #sql = CONCAT('DELETE FROM ',from_schema,'.', v_tname, ' WHERE ',v_pkey,' IN (SELECT ', v_pkey, ' FROM ',to_schema,'.', v_tname, ') limit ',v_limit,';');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET v_deleted=v_deleted+1;
IF v_deleted = v_limit THEN
commit;
SET v_deleted=0;
END IF;
SELECT CONCAT('Deleting...',v_tname);
END IF;
UNTIL done END REPEAT;
CLOSE table_cursor;
END$$
DELIMITER ;
In my MySQL setup I have about a dozen database with hundreds of tables where all id fields are defined with type varchar(20). Per database there are a few thousand of these fields. These fields need to be altered into varchar(36).
In order to make this happen I have created a stored procedure, that:
gets all appropriate schemas;
get the tables of the schemas;
loop through all the columns and when the column type = 'varchar(20) alter the column to varchar(36).
The content of the procedure is available below. But instead of altered column types I get nothing. Meaning there is something wrong. But what is it?
Can you help me out?
DELIMITER $$
DROP PROCEDURE IF EXISTS `get_database`$$
DROP PROCEDURE IF EXISTS `get_table`$$
DROP PROCEDURE IF EXISTS `get_column`$$
DROP PROCEDURE IF EXISTS `alter_column`$$
CREATE PROCEDURE get_database()
BEGIN
DECLARE db_rows INT;
DECLARE dbI INT DEFAULT 1;
DECLARE db_name VARCHAR(255);
DECLARE db_names CURSOR FOR SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME LIKE '%ofb%';
SET #enabled = TRUE;
select FOUND_ROWS() into db_rows;
open db_names;
db_loop: LOOP
if dbI > db_rows THEN
CLOSE db_names;
LEAVE db_loop;
end if;
FETCH db_names INTO db_name;
-- database found
if db_name then
call get_table(db_name);
end if;
SET #dbI = #dbI + 1;
END LOOP db_loop;
END $$
CREATE PROCEDURE get_table(db_name VARCHAR(255))
BEGIN
DECLARE tn_rows INT;
DECLARE tnI INT DEFAULT 1;
DECLARE table_name VARCHAR(255);
DECLARE table_names CURSOR FOR SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = db_name;
SET #enabled = TRUE;
SET tnI = 1;
SET #enabled = TRUE;
select FOUND_ROWS() into tn_rows;
open table_names;
table_loop: LOOP
if tnI > tn_rows THEN
CLOSE table_names;
LEAVE table_loop;
end if;
FETCH table_names INTO table_name;
-- table_name found
if table_name then
call get_column(db_name, table_name);
end if;
SET tnI = tnI + 1;
END LOOP table_loop;
END $$
CREATE PROCEDURE get_column(db_name VARCHAR(255), table_name VARCHAR(255))
BEGIN
DECLARE cn_rows INT;
DECLARE cnI INT DEFAULT 1;
DECLARE column_name VARCHAR(255);
DECLARE column_names
CURSOR FOR SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = db_name and TABLE_SCHEMA = table_name;
SET #enabled = TRUE;
SET cnI = 1;
select FOUND_ROWS() into cn_rows;
open column_names;
column_loop: LOOP
if cnI > nn_rows THEN
CLOSE column_names;
LEAVE column_loop;
end if;
FETCH column_names INTO column_name;
-- column_name found
if column_name then
call alter_column(db_name, table_name, column_name);
end if;
SET cnI = cnI + 1;
END LOOP column_loop;
END $$
CREATE PROCEDURE alter_column(db_name VARCHAR(255), table_name VARCHAR(255), column_name VARCHAR(255))
BEGIN
DECLARE dtype VARCHAR(255);
declare data_type
CURSOR FOR SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = table_name and TABLE_NAME = table_name AND COLUMN_NAME = column_name;
open data_type;
fetch data_type into dType;
if dType = 'varchar(20)' then
SET #ddl = CONCAT('alter table ', db_name, '.',table_name, ' modify column (', column_name, ' VARCHAR(36))');
PREPARE STMT FROM #ddl;
EXECUTE STMT;
end if;
END $$
DELIMITER ;
Your help is appreciated.
Best regards
I was in need of these procedures, and see some changes I made, that worked:
CREATE PROCEDURE get_database()
BEGIN
DECLARE _table_name VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;
DECLARE table_names CURSOR FOR
SELECT table_name
FROM INFORMATION_SCHEMA.TABLES WHERE
TABLE_SCHEMA like '%ofb%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN table_names;
table_loop: LOOP
FETCH table_names INTO _table_name;
IF finished = 1 THEN
CLOSE table_names;
LEAVE table_loop;
END IF;
CALL get_column('%ofb%', _table_name);
END LOOP table_loop;
END
CREATE PROCEDURE get_column(db_name VARCHAR(255), table_name VARCHAR(255))
BEGIN
DECLARE _column_name VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;
DECLARE column_names CURSOR FOR
SELECT column_name FROM
INFORMATION_SCHEMA.COLUMNS
WHERE table_schema LIKE db_name AND
TABLE_NAME = _table_name AND
DATA_TYPE = "varchar" AND
CHARACTER_MAXIMUM_LENGTH = 20
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN column_names;
column_loop: LOOP
FETCH column_names INTO _column_name;
IF finished = 1 THEN
CLOSE column_names;
LEAVE column_loop;
END IF;
SET #ddl = CONCAT('ALTER TABLE ', db_name, '.',_table_name, ' MODIFY COLUMN ', _column_name, ' VARCHAR(36) NULL');
PREPARE STMT FROM #ddl;
EXECUTE STMT;
END LOOP column_loop;
END
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 ;
SOLVED:
This works:
DROP PROCEDURE IF EXISTS drop_all_tables_from_specified_database;
DELIMITER $$
CREATE PROCEDURE drop_all_tables_from_specified_database(IN dbname CHAR(50))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tblname CHAR(50);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = dbname COLLATE utf8_general_ci;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET foreign_key_checks = 0;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tblname;
IF done THEN
LEAVE read_loop;
END IF;
SET #database_name = dbname;
SET #table_name = tblname;
SET #sql_text = CONCAT('DROP TABLE ', #database_name, '.' , #table_name, ';');
PREPARE stmt FROM #sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur1;
SET foreign_key_checks = 1;
END$$
DELIMITER ;
CALL drop_all_tables_from_specified_database('test');
DROP PROCEDURE drop_all_tables_from_specified_database;
I am trying to create a procedure that deletes all tables inside a database. I have saved this code inside a file tear-down.sql:
CREATE PROCEDURE drop_all_tables_from_specified_database()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE table_to_drop VARCHAR(255);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema='test';
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO table_to_drop;
IF done:
LEAVE read_loop;
END IF;
DROP TABLE `test`.table_to_drop;
END LOOP;
CLOSE cur1;
END;
When I then do inside MySQL command line tool:
mysql> source tear-down.sql
I get a massive error:
I don't understand the error I get and I cannot figure out what's wrong. Anybody can spot an error in this procedure?
EDIT:
My current code:
DROP PROCEDURE IF EXISTS drop_all_tables_from_specified_database;
DELIMITER $$
CREATE PROCEDURE drop_all_tables_from_specified_database(IN dbname CHAR(50))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tblname CHAR(50);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = dbname;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tblname;
IF done THEN
LEAVE read_loop;
END IF;
DROP TABLE dbname.tblname;
END LOOP;
CLOSE cur1;
END$$
DELIMITER ;
CALL drop_all_tables_from_specified_database('test');
DROP PROCEDURE drop_all_tables_from_specified_database;
Now it runs ok but it doesn't delete the tables. I get this response:
It looks like you will need to set an alternative DELIMITER:
DELIMITER $$
CREATE PROCEDURE drop_all_tables_from_specified_database()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE table_to_drop VARCHAR(255);
DECLARE cur1 CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema='test';
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO table_to_drop;
/* This might need to be 'IF done <> FALSE THEN' */
IF done THEN
LEAVE read_loop;
END IF;
DROP TABLE `test`.table_to_drop;
END LOOP;
CLOSE cur1;
END$$
DELIMITER ;
It should be IF done THEN not IF done: . Also done variable does not get updated so you might get an infinite loop in there. Take a look at fetch cursor into.