Dynamic add column with loop - mysql

I'd like to create a dynamic procedure wich will generate the columns for me automatically but somethings wrong. I have to do this a few times in my program and I don't really want to do it manually.
So thats the code that I used before
DELIMITER $$
DROP PROCEDURE IF EXISTS RepeatLoopProc$$
CREATE PROCEDURE RepeatLoopProc()
BEGIN
DECLARE x INT;
DECLARE str VARCHAR(255);
Declare #sql nvarchar(4000);
SET x = 0;
REPEAT
SET str = '';
SET str = CONCAT(str,'ossz_levon_het_',x);
SET x = x + 1;
set #sql='ALTER TABLE telephelyi_teszt ADD '+ str +'DOUBLE NULL';
execute #sql;
UNTIL x > 50
END REPEAT;
END$$
DELIMITER ;
I've got a syntax error near the Declare #sql nvarchar(4000); line any ideas?

When you use DECLARE to create local variables in a stored procedure, don't use the # prefix. Those are for session variables.
But you shouldn't DECLARE the variable anyway. Prepared statements don't work with local variables, only session variables. You don't have to declare session variables.
Your ALTER TABLE statement has an error. You didn't put a space after the column name and before DOUBLE. In other words, the statement will be like the following, which will cause a syntax error wen you execute it.
ALTER TABLE telephelyi_teszt ADD ossz_levon_het_1DOUBLE NULL
You didn't PREPARE the statement. You can't just EXECUTE a string as a statement. See examples in the manual on prepared statements.
It's probably bad design to create 50 columns in any table with identical content. Consider creating a second table, with one column ossz_levon_het and a reference back to your parent table telephelyi_teszt. This is the recommendation of First Normal Form to avoid repeating groups of columns.

Related

Using a cursor in a stored procedure to loop rows MySQL

Scenario: I have a stored procedure that gets data from a table based on 2 inputs: a date and a string (which is a column name). The first procedure is called from another procedure which uses a cursor to loop through rows of a table and pass each row to the string of the first procedure (column names to be checked). My input for the second procedure (which is the one to be called directly) is the date.
Issue: My first procedure is running fine when I call it on its own. My second procedure is throwing some syntax errors that I don't know how to fix.
Obs: I already check some other answers here on this topic
such as Using Cursor in a Loop of a stored procedure and How can I loop through all rows of a table? (MySQL) . Actually my second procedure is now a modified version of a query I found on SE https://dba.stackexchange.com/questions/138549/mysql-loop-through-a-table-running-a-stored-procedure-on-each-entry
Issue: Currently, the code is throwing an error at line 5, in my declare of #colval.
Code:
-- Procedure for looping through rows of `wanted_columns` table:
delimiter $$
drop procedure if exists `data_check_loop` $$
create procedure `data_check_loop`(`wanted_date` date)
begin
set #dateval = `wanted_date`;
declare colval string default null;
-- boolean variable to indicate cursor is out of data
declare done tinyint default false;
-- declare a cursor to select the desired columns from the desired source table
declare cursor1
cursor for
select t1.c1
from `wanted_columns` t1;
-- catch exceptions
declare continue handler for not found set done = true;
-- open the cursor
open cursor1;
my_loop:
loop
fetch next from cursor1 into colval;
if done then
leave my_loop;
else
call `set_column_stats`(colval, dateval);
end if;
end loop;
close cursor1;
end $$
delimiter ;
Question: Any ideas on how to fix this?
You have a couple of problems in your procedure. Firstly, as described in the manual:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
So you need to move your
set #dateval = `wanted_date`;
after all the DECLAREs (including the cursor and continue handler).
Secondly, your declaration of colval is incorrect, string is not a valid data type and should be replaced with text:
declare colval text default null;

Unable to create a cursor in a stored procedure from mysql

I want to create a Cursor in a stored procedure from mysql. The question is, it's giving a error when the Cursor is created after the variable initialization. Is there any solution for it.
DELIMITER //
Create procedure sp_JB_Securities_Second_row_Insert()
BEGIN
DECLARE Rw_Count int;
set Rw_Count = (select count(*) from JB_Security_Detials):
DECLARE cur1 CURSOR FOR select title from JB_Security_Detials limit 27, Rw_Count;
END //
DELIMITER ;
It has been pointed out by others (P.Salmon) that the order for DECLARING variables and the CURSOR is significant and it is very specific.
e.g.
Variable declarations must appear before cursor or handler
declarations.
and
Cursor declarations must appear before handler declarations and after
variable and condition declarations.
However, switching the order around is not going to help you here because you are looking to use RW_Count in your LIMIT clause and setting the variable before the CURSOR declaration is causing the error. This restriction also means that the only way you could use a variable in the LIMIT clause is if you pass it in as a parameter to the procedure (which you probably don't want to do).
Fortunately, none of that necessary as you don't really need to know the number of rows in the table to use OFFSET with LIMIT.
There's a nice example in the documentation for the SELECT statement
To retrieve all rows from a certain offset up to the end of the result
set, you can use some large number for the second parameter. This
statement retrieves all rows from the 96th row to the last:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
So, the solution here is to just remove the RW_Count variable completely and add a very BIG number instead.
try this
Create procedure sp_JB_Securities_Second_row_Insert()
BEGIN
DECLARE cur1 CURSOR FOR select title from JB_Security_Detials limit
27,(select count(*) from JB_Security_Detials);
END //
DELIMITER ;
Try this
DELIMITER //
DROP PROCEDURE IF EXISTS sp_JB_Securities_Second_row_Insert()
CREATE PROCEDURE sp_JB_Securities_Second_row_Insert()
BEGIN
DECLARE Rw_Count INT;
DECLARE exit_loop BOOLEAN;
SET Rw_Count = (SELECT COUNT(*) FROM JB_Security_Detials);
DECLARE Rw_Count_cursor CURSOR FOR
"Your Query .............. "
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN Rw_Count_cursor;
-- start looping
out_loop: LOOP
-- read the name from next row into the variables
FETCH Rw_Count_cursor INTO col1,cl2, ...;
"Your Query .............. "
IF exit_loop THEN
CLOSE Rw_Count_cursor;
LEAVE out_loop;
END IF;
END LOOP out_loop;
END//
DELIMITER ;

Cursor Fetch Returns Null

The problem is quite clear but I have tried many things to fix it, including using different variable names than table fields. The fetched value from cursor always returns null. The value that is assigned to the cursor fetch is the same data type (int(11)). What I am doing is to assign fetched key_id value from cursor's select table into #my_key_id int(11) variable but it keeps coming as null.
declare my_key_id int(11); /*variable that will be assigned from the value in cursor*/
DECLARE done INT DEFAULT FALSE; /*for cursor break*/
DECLARE cr_cursor cursor for select key_id from tmp_valuesss; /*cursor declaration*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; /*break thingy*/
open cr_cursor;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
select #my_key_id;
FETCH cr_cursor INTO my_key_id;
END LOOP;
close cr_cursor;
You are mistaking User Variables (the ones with an # sign) with Local Variables (the ones with DECLARE).
Your User Variable was never set and thus always null.
Also, DEALLOCATE any PREPARE var.
The Fetch was moved up to occur at the beginning of LOOP.
drop procedure if exists calculate_thingy;
delimiter $$
CREATE PROCEDURE calculate_thingy
(
IN table_name VARCHAR(100)
)
BEGIN
DECLARE SQL_STATEMENT NVARCHAR(8000);
drop table if exists tmp_valuesss;
SET #SQL_STATEMENT = CONCAT('CREATE TABLE IF NOT EXISTS tmp_valuesss AS (SELECT * FROM ', table_name, ')');
PREPARE STMT FROM #SQL_STATEMENT;
EXECUTE STMT;
DEALLOCATE PREPARE STMT; -- Drew added -------------------
alter table tmp_valuesss add the_field float;
begin
declare my_key_id int(11); /*variable that will be assigned from the value in cursor*/
DECLARE done INT DEFAULT FALSE; /*for cursor break*/
DECLARE cr_cursor cursor for select key_id from tmp_valuesss; /*cursor declaration*/
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; /*break thingy*/
open cr_cursor;
read_loop: LOOP
FETCH cr_cursor INTO my_key_id;
IF done THEN
LEAVE read_loop;
END IF;
select my_key_id;
END LOOP;
close cr_cursor;
end;
END $$
DELIMITER ;
A few things to note. First, the reason why the whole block is presented above is to aid the future visitor here that may be having a problem with creating the stored proc due to the DELIMITER issue many struggle with. Also, the drop at the beginning is important for edits to the proc the 2nd time and thereafter.
Also, this is clearly just a testing a concept stored proc that you presented. Meaning, by doing a select my_key_id; in the LOOP, you are effectively creating an additional resultset on the consumer side (that which called the stored proc with the call statement). Whether or not you are equipped to handle multiple result sets coming back in your code will impact your review of this.
Also, it is driven by the state of the table name you pass as a parameter. So if that table contains values or nulls, you get what you get based on your code and your decision to pass that table name. A table that allegedly contains the column key_id because that is the way you wrote the stored procedure to begin with.
A view below is of it working, with multiple result sets.
That above image shows a table that had 2 rows in it for fish and frog. Two resultsets were returned (that is how you coded it). I Highlighted the second result set, and it showed the value coming back from it (which was id 2) ... the last row that occurred before the LOOP was finished.
Instead of attempting to edit this answer for a third time, I recommend you join me in chat in the link I gave in a comment under your question.

Add columns to mySQL table with loops

I'm fairly new to mySQL. Let's say I'm adding columns to my table like so:
ALTER TABLE table ADD client_input_2.0_1 LONGTEXT;
And I would like to add a number of similar sequential columns, i.e.
ALTER TABLE table ADD client_input_2.0_2 LONGTEXT;
ALTER TABLE table ADD client_input_2.0_3 LONGTEXT;
ALTER TABLE table ADD client_input_2.0_4 LONGTEXT;
etc. all the way up to a large enough number that this will take quite some time if I do this manually. In my case, 2.0 represents a section/part, and the last number represents a question number, which could be anywhere from 1-50 or so depending on the section, so manually creating this table would take a lot of time.
Is there a way for me to do this in a script using some sort of loop, incrementing the col# each time?
Much appreciated,
Edited code
try using a stored procedure
DELIMITER $$
DROP PROCEDURE IF EXISTS RepeatLoopProc$$
CREATE PROCEDURE RepeatLoopProc()
BEGIN
DECLARE x INT;
DECLARE str VARCHAR(255);
Declare #sql nvarchar(4000);
SET x = 0;
REPEAT
SET str = '';
SET str = CONCAT(str,'client_input_2.0_',x);
SET x = x + 1;
set #sql='ALTER TABLE table_name ADD '+ str +' column-definition';
exec sp_executesql #sql;
UNTIL x > 50
END REPEAT;
END$$
DELIMITER ;
Hope this will help you.
I think maybe you should use another approach:
ALTER TABLE table ADD col LONGTEXT, ADD col_index INT.
and use col_index to track the col's purpose

MySQL stored procedure troubles

Basically i'm going to run this procedure anytime a student enrolls/drops a course.
I'm trying to set student_total = # of students in a course, then update that corresponding section with (student_total + 1) i'm having trouble finding good documentation for stored procedures. I'm getting an error on my Declare student_total int; line. What am i not doing correct?
DELIMITER $$
CREATE PROCEDURE `mydb`.`update_seats` (IN section_ID varchar(20))
BEGIN
SET #section_id=section_id;
DECLARE student_total int;
-- count the number of students in the course --
SET student_total = SELECT count(student_ID) from course
WHERE section_ID = #section_id;
Update Section SET students_enrolled = (student_total + 1)
WHERE section_ID = #section_id;
END
Problems
Error 1
From MySql documentation:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
So, you should move DECLARE... statement before the SET #section_id... statement.
Error 2
You are trying to select a value into a variable using invalid snytax! You should use SELECT ... INTO instead of SET ... = SELECT ... (which is invalid syntax).
Removing Redundancy
No need to assign parameter (section_ID) to a global variable (#section_ID). You can simply change the parameter name to avoid name collision with section.section_ID column.
Solution
DELIMITER ;;
CREATE PROCEDURE `update_seats` (IN p_section_ID VARCHAR(20))
BEGIN
DECLARE student_total INT;
SELECT count(student_ID)
INTO student_total
FROM course
WHERE section_ID = p_section_ID;
UPDATE section
SET students_enrolled = (student_total + 1)
WHERE section_ID = p_section_ID;
END;;
DELIMITER ;
You're using the command line tool, yes?
It would be helpful to know the error message you received but based off the code you posted I don't see where you reset the delimiter command after the BEGIN...END block.
Taken from http://dev.mysql.com/doc/refman/5.1/en/stored-programs-defining.html