I know this query for changing the charset and collation of mysql table.
alter table <some_table> convert to character set utf8 collate utf8_unicode_ci;
But I need a query for changing all the tables in a db. Is there any possible solutons.
I have written this procedure to execute statements for every table in a database:
DROP PROCEDURE IF EXISTS sp_forEveryTable;
DELIMITER $$
CREATE PROCEDURE sp_forEveryTable(IN p_schema varchar(50), IN p_stmt varchar(100))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_tbl varchar(50);
DECLARE cur CURSOR FOR SELECT table_name FROM information_schema.tables WHERE table_schema = p_schema;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_tbl;
IF done THEN
LEAVE read_loop;
END IF;
SET #sql := REPLACE(p_stmt, '?', v_tbl);
IF (UPPER(p_stmt) LIKE 'SELECT %') THEN
SET #sql := CONCAT('SELECT "', v_tbl, '", ', SUBSTRING(#sql FROM 7));
ELSE
SELECT v_tbl AS 'Execute statement for following table:';
END IF;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
Use it like this:
CALL sp_forEveryTable('your_database_name', 'ALTER TABLE ? CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci');
To have the tables created in the future in this database have the utf8 character set and collation as default use the statement given in this answer.
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 have written a mysql procedure to compare two databases and add missing tables and columns but it show error i counld not spot the error i that procedure pls help me out to clear that error
DELIMITER $$
CREATE PROCEDURE database_comparison(IN original_db varchar(255),IN compare_db varchar(255))
BEGIN
DECLARE table_name_o varchar(255);
DECLARE column_name_o varchar(255);
DECLARE cursor_sts int default 0;
DROP TABLE IF EXISTS temp_db.original_database_list;
create temporary table temp_db.original_database_list SELECT TABLE_NAME,COLUMN_NAME,'table not exists' as flag_t,'column not exists' as flag_c FROM information_schema.`COLUMNS` where TABLE_SCHEMA=original_db and TABLE_NAME not like 'z%' and TABLE_NAME not like '%bk%';
DROP TABLE IF EXISTS temp_db.compare_database_list;
create temporary table temp_db.compare_database_list SELECT TABLE_NAME,COLUMN_NAME,'table not exists' as flag_t,'column not exists' as flag_c FROM information_schema.`COLUMNS` where TABLE_SCHEMA=compare_db and TABLE_NAME not like 'z%' and TABLE_NAME not like '%bk%';
update temp_db.original_database_list a join temp_db.compare_database_list b on a.TABLE_NAME=b.TABLE_NAME set a.flag_t='',b.flag_t='';
update temp_db.original_database_list a join temp_db.compare_database_list b on a.TABLE_NAME=b.TABLE_NAME and a.COLUMN_NAME=b.COLUMN_NAME set a.flag_c='',b.flag_c='';
DECLARE table_cursor CURSOR FOR select distinct TABLE_NAME from temp_db.original_database_list where flag_t<>'';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_sts=1;
OPEN table_cursor;
table_loop:LOOP
IF cursor_sts=1 THEN
SET cursor_sts=0;
LEAVE table_loop;
END IF;
FETCH table_cursor INTO table_name_o;
create table compare_db.table_name_o like original_db.table_name_o;
END LOOP table_loop;
CLOSE table_cursor;
SET table_name_o='';
DECLARE column_cursor CURSOR FOR select distinct TABLE_NAME,COLUMN_NAME from temp_db.original_database_list where flag_t='' and flag_c<>'';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_sts=1;
OPEN column_cursor;
column_loop:LOOP
IF cursor_sts=1 THEN
LEAVE table_loop;
END IF;
FETCH column_cursor INTO table_name_o,column_name_o;
SET #query =(SELECT concat('alter table `',compare_db,'`.`',table_name_o,'` add `',column_name_o,'` ',column_type,' not null;') FROM information_schema.`COLUMNS` where TABLE_NAME=table_name_o and a.COLUMN_NAME=column_name_o and TABLE_SCHEMA=original_db);
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP column_loop;
CLOSE column_cursor;
END $$
DELIMITER ;
**this is the corrected procedure it works**
DELIMITER $$
DROP PROCEDURE IF EXISTS database_comparison$$
CREATE PROCEDURE database_comparison(IN original_db varchar(255),IN compare_db varchar(255))
BEGIN
DECLARE table_name_o varchar(255);
DECLARE column_name_o varchar(255);
DECLARE cursor_sts int default 0;
DEClARE table_cursor CURSOR FOR
select distinct TABLE_NAME from temp_db.original_database_list where flag_t<>'';
DECLARE column_cursor CURSOR FOR
select distinct TABLE_NAME,COLUMN_NAME from temp_db.original_database_list where flag_t='' and flag_c<>'';
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET cursor_sts=1;
DROP TABLE IF EXISTS temp_db.original_database_list;
create table temp_db.original_database_list SELECT TABLE_NAME,COLUMN_NAME,'table not exists' as flag_t,'column not exists' as flag_c FROM information_schema.`COLUMNS` where TABLE_SCHEMA=original_db and TABLE_NAME not like 'z%' and TABLE_NAME not like '%bk%';
DROP TABLE IF EXISTS temp_db.compare_database_list;
create table temp_db.compare_database_list SELECT TABLE_NAME,COLUMN_NAME,'table not exists' as flag_t,'column not exists' as flag_c FROM information_schema.`COLUMNS` where TABLE_SCHEMA=compare_db and TABLE_NAME not like 'z%' and TABLE_NAME not like '%bk%';
ALTER TABLE temp_db.original_database_list ADD index(TABLE_NAME,COLUMN_NAME);
ALTER TABLE temp_db.compare_database_list ADD index(TABLE_NAME,COLUMN_NAME);
update temp_db.original_database_list a join temp_db.compare_database_list b on a.TABLE_NAME=b.TABLE_NAME set a.flag_t='',b.flag_t='';
update temp_db.original_database_list a join temp_db.compare_database_list b on a.TABLE_NAME=b.TABLE_NAME and a.COLUMN_NAME=b.COLUMN_NAME set a.flag_c='',b.flag_c='';
OPEN table_cursor;
table_loop:LOOP
FETCH table_cursor INTO table_name_o;
IF cursor_sts=1 THEN
SET cursor_sts=0;
LEAVE table_loop;
END IF;
SET #query1 =concat('create table ',compare_db,'.',table_name_o,' like ',original_db,'.',table_name_o);
PREPARE stmt1 FROM #query1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
END LOOP table_loop;
CLOSE table_cursor;
SET table_name_o='';
OPEN column_cursor;
column_loop:LOOP
FETCH column_cursor INTO table_name_o,column_name_o;
IF cursor_sts=1 THEN
LEAVE column_loop;
END IF;
SET #query =(SELECT concat('alter table `',compare_db,'`.`',table_name_o,'` add `',column_name_o,'` ',column_type,' not null;') FROM information_schema.`COLUMNS` where TABLE_NAME=table_name_o and COLUMN_NAME=column_name_o and TABLE_SCHEMA=original_db);
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP column_loop;
CLOSE column_cursor;
END $$
DELIMITER ;
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 have a procedure call that updates a set of data and then returns the data set for my to render. Everything works fine except that, I cant do both operations at once. If I do the update, then the procedure, won´t return any value and vice versa. I have seen some answers suggesting to use temptables but I could not find how to retrieve the dataset. I appreciate any help even if it comes to improving my query.
CREATE DEFINER=`root`#`localhost` PROCEDURE `prueba`(IN `idUsuario` INT)
MODIFIES SQL DATA
BEGIN
DECLARE flag INT DEFAULT FALSE;
DECLARE done INT DEFAULT FALSE;
DECLARE idNotificacion INT DEFAULT 0;
DECLARE cont INT DEFAULT 0;
DECLARE resultset CURSOR FOR SELECT id FROM notificaciones WHERE involvedA_idUsuario=idUsuario AND active=1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN resultset;
SET #query = "SELECT * FROM notificaciones n WHERE n.id IN('null'";
the_loop: LOOP
FETCH resultset INTO idNotificacion;
IF done THEN
LEAVE the_loop;
END IF;
SET cont = cont + 1;
SET flag = TRUE;
SET #query = CONCAT(#query," , " ,idNotificacion);
UPDATE notificaciones SET active=0 WHERE id=idNotificacion;
END LOOP the_loop;
CLOSE resultset;
IF flag THEN
SET #query = CONCAT(#query, ")");
PREPARE stmt FROM #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END
Do you really need a cursor? An option like this, maybe it can be useful:
/* Procedure structure for procedure `prueba` */
/*!50003 DROP PROCEDURE IF EXISTS `prueba` */;
DELIMITER $$
CREATE PROCEDURE `prueba`(`idusuario` INT)
BEGIN
DECLARE `ids` LONGTEXT DEFAULT NULL;
SELECT GROUP_CONCAT(`id`) INTO `ids`
FROM `notificaciones`
WHERE `involveda_idusuario` = `idusuario` AND `active` = 1;
IF (`ids` IS NOT NULL) THEN
SET #`stmt` := CONCAT('UPDATE `notificaciones`
SET `active` = 0
WHERE `id` IN (', `ids`, ')');
PREPARE `exec` FROM #`stmt`;
EXECUTE `exec`;
SET #`stmt` := CONCAT('SELECT `id`, `involveda_idusuario`, `active`
FROM `notificaciones` `n`
WHERE `n`.`id` IS NULL OR `n`.`id` IN (', `ids`, ')');
PREPARE `exec` FROM #`stmt`;
EXECUTE `exec`;
DEALLOCATE PREPARE `exec`;
END IF;
END$$
DELIMITER ;
You must be careful with GROUP_CONCAT and the system variable group_concat_max_len.
SQL Fiddle demo
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 ;