How to create a create table statement in a loop in mysql - mysql

I want to create multiple tables with just one statement (query).
Loop
start
(
create table a
)
a =a +1
end loop
So say it has to create 100 tables labeled as TABLE1, TABLE2, ...

Try the following procedure.
DROP PROCEDURE IF EXISTS `createTableProcTest`;
delimiter //
CREATE PROCEDURE `createTableProcTest`()
BEGIN
DECLARE count INT Default 0;
simple_loop: LOOP
SET #a := count + 1;
SET #statement = CONCAT('Create table Table',#a,' ( name VARCHAR(70), age int );');
PREPARE stmt FROM #statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET count = count + 1;
IF count=100 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END//
In order to execute just do the following:
Call createTableProcTest();
By executing the above procedure 100 tables will be created having name table1,...,table100.
And the table structure would look like following:
N:B: Procedure execution might take several seconds. Don't be impatient.

You need give us more details but, I think is easier to call a stored procedure, inside the loop, to create the procedure.
You need to create a procedure to create the tables you need and call this procedure inside the loop.
Ex:
CREATE PROCEDURE SP_Create_Table(IN tableName VARCHAR(50)) BEGIN SET
#sql = CONCAT('CREATE TABLE ', tableName, '(column1 INT(11))');
PREPARE stmt FROM #sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END
Now, call the create table procedure inside the loop
DELIMITER // CREATE FUNCTION CalcIncome ( starting_value INT ) RETURNS
INT BEGIN
DECLARE income INT; SET income = 0; label1: WHILE income <=
50 DO
call SP_Create_Table(CONVERT(VARCHAR(50),starting_value)); END WHILE label1; RETURN income; END; // DELIMITER;

Related

Creating a Procedure prior to the creation of database and table

I am trying to create a Procedure during the creation of a database, the mysql query is as follows:
CREATE DATABASE database_Sensor1;
USE database_Sensor1;
CREATE TABLE Persons(id int NOT NULL);
DELIMITER //
CREATE PROCEDURE MYLOOP() IF database_Sensor1 EXISTS
BEGIN
DECLARE i int;
DECLARE str varchar(255);
SET i = 0;
WHILE i < 32 DO
SET str = CONCAT('col_',i);
SET #sql = CONCAT('ALTER TABLE persons ADD ',str,' float;');
SET i = i + 1;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END WHILE;
END
DELIMITER ;
CALL MYLOOP();
But I get this error:
#1305 - PROCEDURE database_sensor1.MYLOOP does not exist
I am trying to use the Procedure to Loop the table creation by quickly altering the table to add 32 columns in so that I can run another .php to add in the values.
CREATE DATABASE database_Sensor1;
USE database_Sensor1;
CREATE TABLE database_Sensor1.Persons(id int NOT NULL);
DELIMITER //
CREATE PROCEDURE database_Sensor1.MYLOOP()
BEGIN
DECLARE i int;
DECLARE str varchar(255);
SET i = 0;
WHILE i < 32 DO
SET str = CONCAT('col_',i);
SET #sql = CONCAT('ALTER TABLE database_Sensor1.persons ADD ',str,' float;');
SET i = i + 1;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END WHILE;
END
//
DELIMITER ;
CALL MYLOOP();
Editions:
IF database_name EXISTS construction not exists. Removed. See edition 3.
Procedure creation code is not finalized with delimiter. Added.
The database in which the procedure must be created is not specified explicitly. Added. If the database not exists then the error will be generated. The same with the table name.

MYSQL error while executing SQL query stored in a column

I have two tables,
execution:
execution_id | order_id | execution_date
1 1 2014-03-16
2 1 2014-03-17
and queries:
query_name | code
CNT_EXEC | SELECT COUNT(execution_id) FROM `execution`
We have query defined in a column above. I am trying to execute this query using my code below;
DELIMITER //
DROP PROCEDURE IF EXISTS query_execute //
CREATE PROCEDURE query_execute()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE s_query varchar(255);
DECLARE c_queries CURSOR FOR
SELECT code FROM queries;/*since there are more than one queries in the actual query table*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
OPEN c_queries;
getquery: LOOP
FETCH c_queries INTO s_query;
IF finished = 1 THEN
LEAVE getquery;
END IF;
/*run the query*/
SET #sql = s_query;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
END //
DELIMITER ;
/*next I am trying to invoke the procedure and find the results*/
CREATE PROCEDURE queriesExecution()
BEGIN
SELECT query_name, query_execute() AS val
FROM queries;
END
Going by the MySQL documentation, it seems I am using the correct procedure to create the procedure.But here is the error I am getting;
ERROR 1064 (42000) in the pre-written template: 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 '' at line 5`.
As i already wrote in my comment, your approach doesn't work .
But you can change it a bit
First:
Change your queries, because you need a result
CREATE TABLE queries (
`query_name` VARCHAR(8),
`code` VARCHAR(355)
);
INSERT INTO queries
(`query_name`, `code`)
VALUES
('CNT_EXEC', 'SELECT COUNT(execution_id) INTO #result FROM `execution`');
As you can see the result is put into a user defined variable. so that ot can be used in the INSERT INT myresult
DELIMITER //
DROP PROCEDURE IF EXISTS query_execute //
CREATE PROCEDURE query_execute()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE s_query varchar(255);
DECLARE c_queries CURSOR FOR
SELECT code FROM queries;/*since there are more than one queries in the actual query table*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
CREATE TEMPORARY TABLe myresults(`query` varchar(255), result INT);
OPEN c_queries;
getquery: LOOP
FETCH c_queries INTO s_query;
IF finished = 1 THEN
LEAVE getquery;
END IF;
/*run the query*/
SET #sql = s_query;
PREPARE stmt FROM #sql;
EXECUTE stmt;
INSERT INTO myresults VALUES (s_query,#result);
DEALLOCATE PREPARE stmt;
END LOOP;
SELECT * FROM myresults;
DROP TEMPORARY TABLE myresults;
END //
DELIMITER ;
when you now call CALL query_execute();
you get
query result
SELECT COUNT(execution_id) INTO #result FROM `execution` 2
Of course as you add queries, you will get more rows.
this now assumes you get only INTEGER back in your queries, if not you must change the datatype.
This also only works, because your query returns only 1 result, if get more rows you can't use the user defined variables and you have to look for another approach.

How to write MySQL stored procedure for adding a range of records between two dates

I'm trying to write a stored procedure in MySQL that will receive two dates. A from date and a two date. I've written stored procedures before but I'm stumped as to where to start with this.
How can I code a stored procedure that, when it received 20170101 and 20170110 it adds the following to a table
20170101
20170102
20170103
20170104
20170105
20170106
20170107
20170108
20170109
20170110
I don't simply want to add one to each value as they are dates and 20170132 doesn't exist in reality.
Thank you everyone
This might help you.
CREATE TABLE IF NOT EXISTS table_name (field_name VARCHAR(255));
DELIMITER $$
USE `test`$$
DROP PROCEDURE IF EXISTS `test1`$$
CREATE PROCEDURE `test1`(
IN pi_date_from DATE,
IN pi_date_to DATE
)
READS SQL DATA
BEGIN
SET #countRecordToAdd = 0;
SET #i = 0;
SET #query = 'INSERT INTO table_name (field_name) VALUES ';
SELECT
DATEDIFF(pi_date_to, pi_date_from)
INTO
#countRecordToAdd
;
IF #countRecordToAdd > 0
THEN
label1: LOOP
SET #query = CONCAT(
#query,
" (date_add(\"", pi_date_from, "\", INTERVAL ", #i, " DAY)),"
);
SET #i = #i + 1;
IF #i <= #countRecordToAdd THEN ITERATE label1;END IF;
LEAVE label1;
END LOOP label1;
PREPARE stmt FROM TRIM(TRAILING ',' FROM #query);
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END$$
DELIMITER ;

Logic condition to avoid duplicate entries in stored procedure

I have the following stored procedure . I'm trying to insert the users from the table usuaris, whose admin variable is equal to 1, into the table that the stored procedure creates with the name( nombre varchar(50)) that is passed as a parameter.
When the procedure is called, it duplicates the user 'mary' with id 4. I've tried a couple of ways to implement the logic condition in order to avoid the duplication, but still, I'm missing something and I can't get the desired result. In the code below, the logic condition before the insertion is the last thing I've tried. Any ideas?
Thanks.
CREATE DEFINER=`root`#`localhost` PROCEDURE `createNewtable`(nombre varchar(50))
BEGIN
/*variable declaration*/
declare centinela int ;
declare id1 int ;
declare nom1 varchar(50);
declare admin1 enum('0','1') ;
declare cadena varchar(100); /*string to concatenate table creation and insertion*/
/*cursor declaration*/
declare cursor1 cursor for select * from users.usuaris where admin = '1' ;
declare continue handler for not found set #centinela = 1 ;
/*create the table with the name that's passed as parameter*/
set #cadena=concat("create table ",nombre,
"(
id2 int not null primary key,
nom2 varchar(50),
admin2 enum ('0','1')
)" );
prepare stmt from #cadena ;
execute stmt ;
deallocate prepare stmt;
/* loop that fetches the data from the table usuaris and
inserts them into the newly created table. */
set #centinela = 0 ;
open cursor1 ;
bucle: loop
fetch cursor1 into id1,nom1,admin1 ;
if ( centinela = 1 ) then
leave bucle ;
end if ;
/*logic condition to avoid entry duplication */
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end loop bucle;
close cursor1;
END
Here is the single-table database of users :
create database if not exists `users` ;
use `users` ;
create table usuaris(
id int not null auto_increment primary key ,
nom varchar(50),
admin enum ('0','1')
);
insert into usuaris(id,nom,admin)
values
(1,'jose','1'),
(2,'maria','0'),
(3,'frank','1'),
(4,'mary','1'),
(5,'godfrey','0') ;
Also it has to duplicate jose. The reason of duplication - if the IF statement isn't TRUE then you don't set the new #cadena variable BUT anyway execute PREVIOUS #cadena statement. You should move execution into the IF statement also:
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;
Also in SQL you should always try to avoid loops if it possible and use SQL statements instead.
You can replace your loop with one SQL statement:
INSERET INTO NEW_TABLE_NAME_HERE
SELECT id1,nom1,admin1
FROM users.usuaris where admin<>'1'
Further more you can use SELECT INTO statement syntax to automatically create new table without CREATE TABLE statement:
SELECT id1 as id2,
nom1 as nom2,
admin1 as admin2
INTO NEW_TABLE_NAME_HERE
FROM users.usuaris where admin<>'1'
Change ur below code to my new code and try-
Existing Code
if not exists (select * from users.usuaris where admin='1' and id=#id1) then
set #cadena=concat("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
end if;
select #cadena;
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
New Code-
SET #cnt=SELECT count(*) FROM users.usuaris WHERE admin='1' AND id=#id1
IF #cnt>0 THEN
SET #cadena=CONCAT("insert into ",nombre," values( ",id1,",'",nom1,"','",admin1,"')");
prepare stmt from #cadena;
execute stmt ;
deallocate prepare stmt;
end if;

MySQL Pass table name to cursor select

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.