mysql procedure: how can i use table name variables - mysql

I have built a MySQL procedure.
i have to define v_table variable within procedure
Who can help me ?
Thanks
Paolo
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
open cur1;
igmLoop: loop
fetch cur1 into v_column,v_table;
IF done THEN
LEAVE igmLoop;
END IF;
update v_table set v_column=replace(v_column,'à','a`');
end loop igmLoop;
close cur1;
end

Neither table names, nor column names can be dynamic within a stored procedure. You need to assemble the sql statement as a string and execute it using PREPARE, EXECUTE, DEALLICATE PREPARE statements. So, basically, you will create a prepared statement out of your query and execute it.
The linked documentation contains examples as well.

Related

MySQL - how to use variable in where clause of cursor

I usually work with Oracle database and when creating stored procedures one can write cursors where the where clause can have a variable, value of which can be provided at run time.
How do you write something similar in mySQL
Something like
DECLARE myCursor cursor select col1 from table1 where col2 = &1;
OPEN myCursor ("NEW");
You may use user-defined variable and/or local variable (including procedure parameters), both assigned externally and calculated internally, in the cursor definition:
CREATE PROCEDURE test_proc( {parameters} )
BEGIN
DECLARE _id_ INT;
DECLARE cur CURSOR FOR
SELECT id FROM test WHERE val = {variable};
DECLARE EXIT HANDLER FOR NOT FOUND
BEGIN
CLOSE cur;
END;
OPEN cur;
LOOP
FETCH cur INTO _id_;
SELECT _id_;
END LOOP;
END
But you cannot to alter the parameter "on the fly" - after cursor is opened the changes in its parameters will be iglored (during the opening the cursor's text is fixed, the values instead of names are used in fixed text).
Hence when you need to alter dynamically assigned parameter then you must close and reopen the cursor.
DEMO fiddle

Error 1064 in stored procedures

I get this error in the following stored procedure Error Code: 1064. 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 'DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; OPEN cur1; count' at line 13
DELIMITER $$
DROP PROCEDURE IF EXISTS cursor_example
$$
CREATE PROCEDURE cursor_example()
READS SQL DATA
BEGIN
DECLARE i_Name CHAR(3);
DECLARE i_SurfaceArea FLOAT(10,2);
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT Name, SurfaceArea
FROM country
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN cur1;
country_loop:LOOP
FETCH cur1 INTO i_Name, i_SurfaceArea;
IF done=1 THEN
LEAVE country_loop;
END IF;
END LOOP country_loop;
CLOSE cur1;
END;
$$
DELIMITER ;
Just generally how the whole procedure is suppose to work and what is it for.
Thanks.
You were missing a semi-colon after FROM country. Use the following pattern:
DROP PROCEDURE IF EXISTS cursor_example;
DELIMITER $$
CREATE PROCEDURE cursor_example()
READS SQL DATA
BEGIN
DECLARE i_Name CHAR(3);
DECLARE i_SurfaceArea FLOAT(10,2);
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT Name, SurfaceArea
FROM country;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN cur1;
country_loop:LOOP
FETCH cur1 INTO i_Name, i_SurfaceArea;
IF done=1 THEN
LEAVE country_loop;
END IF;
-- right here is where you do stuff with those variables
END LOOP country_loop;
CLOSE cur1;
END;
$$
DELIMITER ;
I don't understand with the example is trying to FETCH cur1 INTO in
the example is for?
Remember that the CURSOR is just a select stmt. It can be really complicated with joins, you name it. But in the end it has a select column list. In your case it has 2 columns coming back. So the FETCH, one row at a time, brings the current row into LOCAL VARIABLES (in the respective order from the cursor list to the variables you list). You declared those LOCAL VARIABLES in your DECLAREs.
When you are out of rows, the HANDLER sets done to 1 and you bail out of the loop.
As for the DELIMITER read the last half of this answer of mine Here.
Just generally how the whole procedure is suppose to work and what is
it for?
Described above mostly. Cursors are for procedural handling of data returned. Allowing you to inject procedural thinking into solving problems. By the way they are terribly slow and should be avoided whenever possible. They are typically a crutch for devs new to SQL that can't get their head into how to do work with sets and relations. That is, the way high performance RDBMS's excel at.
That said, experienced SQL devs are known to use them for tricky situations.

Executing all stored proceedures in one script

i am handing over a project to a another party which i have been doing for some time, in this project i do some modifications to some of the existing table by adding coloumns, renaming coloumns etc.
When i was handling the project what i did was, putting the changes or the modifications inside a stored proceedure once it was run calling the function from the query browser.
stored proceedure
CREATE DEFINER=`my_db`#`10.%` PROCEDURE `alter_test_1`()
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_table VARCHAR(100) DEFAULT "";
DECLARE stmt VARCHAR(500) DEFAULT "";
DECLARE column_cursor CURSOR FOR
SELECT TABLE_NAME FROM `information_schema`.`tables` WHERE table_schema = 'my_db'
AND table_name LIKE 'tot_table_%';
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN column_cursor;
alter_tables: LOOP
FETCH column_cursor INTO v_table;
IF v_finished = 1 THEN
LEAVE alter_tables;
END IF;
SET #prepstmt = CONCAT('ALTER TABLE my_db','.',v_table,' CHANGE OS platform VARCHAR(25);');
PREPARE stmt FROM #prepstmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP alter_tables;
CLOSE column_cursor;
END
afterwards i run
call alter_test_1();
in the query browser.
Now as im handing this over this two step excution is not professional therefore is there a way for me to do this by using another stored proceddure instead running a call alter_test_1() separately... what i mean is there a way to put this call or several call statements inside a stored proceedure and excecute all the call statements in one shot, once that particular stored proceedure is run.
Well... you call a stored procedure within another stored procedure... by calling it.
CREATE PROCEDURE `do_things`()
BEGIN
CALL `alter_test_1`();
CALL `do_more_stuff`();
END
Executing CALL do_things(); will first run your procedure, then one called "do_more_stuff" and then will return. It will terminate at the first unhandled error thrown unless you catch the error with a HANDLER.
That seems like the answer to the question you asked. I'm less clear about whether that was the question you intended to ask, because you talk about "2 step execution," and I don't see what the 2 steps are.
If you are asking how to run a stored procedure (step 2?) without declaring it first (step 1?), then, no, you can't... it's a "stored" procedure, and has to be stored before it can be executed.

selecting in a loop using a cursor

I have got this stored procedure:
DELIMITER //
DROP PROCEDURE IF EXISTS cursor_example//
CREATE PROCEDURE cursor_example()
BEGIN
DECLARE niche_id INT;
DECLARE niche_name VARCHAR(100);
DECLARE curl CURSOR FOR SELECT * FROM `niche`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN curl;
my_loop:LOOP
FETCH curl INTO niche_id,niche_name;
IF done=1 THEN
LEAVE my_loop;
END IF;
END LOOP my_loop;
CLOSE curl;
END//
DELIMITER ;
I want to output everything that the curl fetches. So I thought to put SELECT statement inside or outside the loop..but that wouldnt give me the results that I want. How do I get back all the sql results from that cursor.
And what are the advantages of using cursors compare to other a simple unbound - SELECT statement. I mean I could get the results that I wanted by simply USING a select statement without writing all that cursor code?

Can MySQL triggers be created with dynamic SQL from within a stored procedure?

Is it possible to create a trigger in MySQL using dynamically generated SQL from within a stored procedure? I am executing other dynamically constructed queries in my procedure by preparing a statement, but when I try the same approach to create a trigger I get the following error:
ERROR Code: 1295This command is not supported in the prepared statement protocol yet
From Bug #31625, PREPARED STATEMENT syntax does not allow to create TRIGGERS I see other people have been complaining about the same thing since 2007.
And from the look of WL#2871: Prepare any SQL it has not yet been fixed.
Is there a workaround for this problem? Is there another way of creating triggers with dynamic SQL?
Basically what I am trying to do is dynamically create triggers for recording audit data for inserts on various different tables. I am listing the tables I want to audit in an *audit_tables* table. The stripped-down procedure below iterates over the entries in that table and tries to create the trigger.
drop procedure if exists curtest;
delimiter |
create procedure curtest()
BEGIN
DECLARE done INT DEFAULT 0;
declare tn varchar(16);
declare cur cursor for select table_name from audit_tables;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
fetch cur into tn;
if done then
leave read_loop;
end if;
/* Create the BEFORE INSERT trigger */
set #sql = concat('CREATE TRIGGER audit_', tn, '_bi BEFORE INSERT ON ', tn, '
FOR EACH ROW BEGIN
set new.foo="bar";
END;');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end LOOP;
close cur;
END;
|
delimiter ;
call curtest();
As the error you mention says, the CREATE TRIGGER command is not supported within prepared statements.
I think a more viable option is to use a scripting language that has MySQL bindings, like PHP, to automate the trigger creation. By the way, I just remembered that MySQL Workbench uses Lua as a scripting language for this sort of things.