Looping through various tables MySQL [duplicate] - mysql

This question already has answers here:
MySQL loop through tables
(4 answers)
Closed 2 years ago.
I have a few similarly named tables in MySQL server (e.g: table_1; table_2; table_3 etc.). What I want to do is loop through these tables using a dynamic select query to insert the data into another table, let's say summary_table. Usually what I would do in Python if I create a connection to MySQL server:
for i in range(1,10):
insert = 'Insert into summary_table(*some column names*)'
insert += 'Select (*similar column names*) from table_' + str(i) + ';'
However, I'm not very familiar with the declare and syntax in MySQL server. I tried using this:
drop procedure if exists insert_loop;
delimiter //
create procedure insert_loop()
deterministic
begin
declare i int default 1;
declare tablename varchar(50);
set tablename := concat('table_',i);
while i <= 10 do
insert into summary_table(*some column names*)
select *some column names* from tablename;
set i = i+1;
end while;
end //
delimiter ;
call insert_loop;
But the error returns as schema_name.tablename doesn't exist.
For more information, I'm using MySQL community server version 8.0.23 at the moment for my learning purpose. Any feedback or help how I can solve this error with MySQL is appreciated. Thank you.

you can use EXECUTE command:
drop procedure if exists insert_loop;
delimiter //
create procedure insert_loop()
deterministic
begin
declare i int default 1;
declare tablename varchar(50);
set tablename := concat('table_',i);
while i <= 3 do
set tablename := concat('table_',i);
SET #query = concat('insert into summary_table (id, name, phone) select id, name , phone from ', tablename);
SET #result = NULL;
PREPARE stmt1 FROM #query;
EXECUTE stmt1;
set i = i+1;
end while;
end //
delimiter ;
call insert_loop;

Related

Using cursor to auto create tables

For fun I am messing with phpmyadmin to get myself familiarized with sql but I am stuck at a issue. I am trying to make it so I can automate the organization of employees into tables based on department. I have a procedure I have been working on to use a different table that lists all the departments into a cursor and uses the cursor to fill in the blanks of a create table as query. But when I try to run the creation of the procedure phpmyadmin errors out saying
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near '' at line 3
but in my code line 3 is just BEGIN. What do I need to do to make this work?
CREATE PROCEDURE deptOrganize()
BEGIN
DECLARE counting INT DEFAULT 0;
DECLARE location VARCHAR(MAX);
DECLARE curs1 CURSOR SELECT Department FROM departments;
OPEN curs1;
WHILE counting < 15 DO
FETCH curs1 INTO location;
CREATE TABLE location AS
SELECT * FROM employees
WHERE employees.Department = location ;
END WHILE;
END;
You can't use a variable for the table name in CREATE TABLE. You have to create dynamic SQL with the PREPARE statement.
You also need to use the DELIMITER directive to change the query delimiter from ;, so you can use that as the statement delimiter within the procedure.
And you forgot to increment counting, so you have an infinite loop.
DELIMITER $$
CREATE PROCEDURE deptOrganize()
BEGIN
DECLARE counting INT DEFAULT 0;
DECLARE curs1 CURSOR SELECT Department FROM departments;
OPEN curs1;
WHILE counting < 15 DO
FETCH curs1 INTO #location;
SET #sql = CONCAT('CREATE TABLE ', #location, ' AS
SELECT * FROM employees
WHERE employees.Department = ?') ;
PREPARE stmt FROM #sql;
EXECUTE stmt USING #location;
DEALLOCATE PREPARE stmt;
SET counting = counting + 1;
END WHILE;
END$$

Running a query for each entry in a list of tables

I intend to write a procedure to run a query on each of the tables in a provided list (can be a comma separated list or a table - undecided on that yet)
I started off with creating a while loop to iterate through each element in the provided list. Have been able to extract each element but I don't know how to run a query for that extracted element/table.
DELIMITER $$
DROP PROCEDURE IF EXISTS retain_demo_clients$$
CREATE PROCEDURE retain_demo_clients()
BEGIN
DECLARE counter INT(10);
DECLARE client_tables VARCHAR(255);
DECLARE table_count INT(10);
DECLARE table_in_process VARCHAR(255);
SET counter = 1;
SET table_count = 3;
SET client_tables = 'client_table, somerandomstuff, somemorestuff';
WHILE (counter < table_count +1) DO
SET table_in_process = substring_index(substring_index(client_tables, ',',counter),',',-1);
SELECT table_in_process;
SET counter = counter +1;
END WHILE;
END$$
DELIMITER ;
CALL retain_demo_clients();
I expect to do something like 'select * from table_in_process'. Would also appreciate if there is a better way to loop through the list of tables.
Here is DBFiddle link, if someone wants to tinker: https://www.db-fiddle.com/f/v6EMsiWvXFrBoNLgoZwDVX/1
You can use EXECUTE to run a text that represent a single statement
SET #someQuery = CONCAT('SELECT * FROM ', table_in_process ) ;
PREPARE preparable_stmt FROM #someQuery;
EXECUTE preparable_stmt;

Mysql calling procedure failed when dynamically alter table in it

I want to alter my tables dynamically based on whether the table has specific column.
My database name is summer_cms, and there are over 50 tables in it.
What I want are below:
If a table has a column named add_time, then I would like to add a column add_user_id in it.
Similarly, I would like to add update_user_id in the table if update_time is found.
I know I should get it down in the process of creating the database schemas, but my database has been built and I have to alter it by need.
So I create a procedure to do it:
CREATE PROCEDURE ALTER_SUMMER_TABLE()
BEGIN
DECLARE tableName VARCHAR(64);
DECLARE exitence VARCHAR(64);
DECLARE ntable INT; # number of tables
DECLARE i INT; # index
SET i = 0;
# get the count of table
SELECT COUNT(DISTINCT(TABLE_NAME)) INTO ntable FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'summer_cms';
WHILE i < ntable DO
# select the specific table name into the variable of `tableName`.
SELECT TABLE_NAME INTO tableName
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time'
LIMIT 1 OFFSET i;
# alter table, but I get error in this clause.
ALTER TABLE tableName ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 COMMENT 'add user id';
# check if the table has `update_time`
SELECT TABLE_NAME INTO exitence
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND TABLE_NAME = tableName
AND COLUMN_NAME = 'update_time';
# add `update_user_id` if `update_time` be found.
IF exitence THEN
ALTER TABLE tableName ADD COLUMN `update_user_id` INT NOT NULL DEFAULT 0 COMMENT 'update user id';
END IF;
SET i = i + 1;
END WHILE;
END
But I got an error when I call this procedure.
Procedure execution failed
1146 - Table 'summer_cms.tableName' doesn't exist
Dose anyone could tell me what I was missing or wrong? Any help will be appreciated.
There a a few alterations you can make to your procedure to make it more streamlined as well as getting round a few problems.
First using a cursor to select the table names rather than using the two selects your using. Secondly to use a prepared statement to allow you to dynamically set the table name...
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `ALTER_SUMMER_TABLE`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE tableName VARCHAR(64);
declare cur cursor for SELECT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'summer_cms'
AND COLUMN_NAME = 'add_time';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
open cur;
start_loop: loop
fetch cur into tableName;
if (done = 1 )THEN
LEAVE start_loop;
END IF;
SET #sql = CONCAT('ALTER TABLE ', tableName,' ADD COLUMN `add_user_id` INT NOT NULL DEFAULT 0 ');
PREPARE stmt FROM #sql;
EXECUTE stmt;
end loop;
close cur;
END$$
DELIMITER ;
You could do a few tweaks - only fetch table names where the column doesn't already exist for example.
Here's an example of dynamic sql
drop procedure if exists alter_table;
delimiter //
CREATE DEFINER=`root`#`localhost` procedure alter_table()
begin
declare tablename varchar(20);
set tablename = 'u';
set #sqlstmt = concat('ALTER TABLE ', tableName, ' ADD COLUMN ', char(96), 'add_user_id', char(96), ' INT NOT NULL DEFAULT 0 COMMENT', char(39), 'add user id', char(39),';');
prepare stmt from #sqlstmt;
execute stmt;
deallocate prepare stmt;
end //
delimiter ;
Note I have used ascii backticks and single quotes.

pass IN sql stament to run to a procedure in mysql

I want to create procedure to use limit option either insert into.. with select.. or create table as select.....
I want to use limit to insert only 500K records at a time so I am using while loop I set count3 this time as i am trying to insert 1.5mil records.
call proc1( with long sql statement......................)
DELIMITER //
CREATE PROCEDURE proc1(IN sqllines text)
BEGIN
DECLARE valFrom INT;
DECLARE valTo INT;
DECLARE count INt default 0;
SET #sqlin = sqllines;
SET valFrom = 0;
SET valTo = 500000;
SET #sql = ('#sqlin LIMIT valFrom , valTo');
WHILE count < 3
DO
PREPARE stmt from #sql;
EXECUTE stmt;
SET valFrom = valFrom+500000;
SET valTo = valTo+500000;
set count = count + 1;
END WHILE;
END;
//
DELIMITER ;
Sorry to say, but you cannot pass a variable into a dynamic-SQL statement in T-SQL.
You can find more information in a question that I myself posted here. The answer here has detailed solution on this.

Example MySQL loop to create missing tables

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);