Creating MySQL stored procedures using MySQL - mysql

Is there a way to programmatically create stored procedures using MySQL? I can write a stored procedure to create databases and tables using prepared statements, but I get an error message saying it is not supported to create stored procedures with prepared statements.
I realize I can do this in PHP or Java, but so far I have been keeping all my schema management tools as SQL scripts, and I would like to avoid a second language dependency if I can.

One method you can try is to build the create procedure statement dynamically in SQL, then use select into outfile to dump the statement to local disk, and then source the file to load the procedure into the DB.
Here's a quick example:
set #proc_name = 'my_proc';
set #body1 = 'select ''hello''; ';
set #body2 = 'select ''world''; ';
set #delimiter = '$$';
set #create_proc_stmt = concat(
'create procedure ',
#proc_name,
'() begin ',
#body1,
#body2,
' end ',
#delimiter
);
select #create_proc_stmt into outfile '/tmp/create_proc_stmt.sql';
delimiter $$
\. /tmp/create_proc_stmt.sql
delimiter ;
call my_proc();

I think you can do it by inserting a record into INFORMATION_SCHEMA.ROUTINES table. I haven't tried it, but it should work (one day in the past I forgot to add --routines switch to mysqldump, and later I restored all procedures by dumping this one table).

Related

Use MySQL procedure to change the name of a table

I am trying to create a stored procedure to change the name of an existing table by appending the date to it.
I have only been using MySQL for a short while and cannot see why the code is not working. I'm using MySQL Workbench 8.0 Community to connect to the MySQL database and run the code. In Workbench no errors are returned when I run the code.
The code I have managed to find so far is:
DELIMITER \\
DROP PROCEDURE IF EXISTS `usp_test_dynamic_sql`\\
CREATE PROCEDURE `usp_test_dynamic_sql`()
BEGIN
SET #s = concat('ALTER TABLE MyDashboardTable RENAME TO MyDashboardTable_',replace(date(now()),'-',''));
PREPARE stmt1 FROM #s;
EXECUTE stmt1;
END\\
DELIMITER ;
I have run part of the code, to find what #s is being set to by running:
SET #s = concat('ALTER TABLE MyDashboardTable RENAME TO MyDashboardTable_',replace(date(now()),'-',''));
select #s;
I have then pasted the result for #s
ALTER TABLE MyDashboardTable RENAME TO MyDashboardTable_20200904
This does change the name of the table but I cannot figure out why the stored procedure does not. Any help will be greatly appreciated.
Execute your SP as
CALL usp_test_dynamic_sql();
You may also want to modify your
replace(date(now()),'-','')
with
DATE_FORMAT(NOW(),'%Y%m%d')
Even though it's not absolutely necessary. If you do, do not leave spaces or use '-' or '/' between the formats since MySQL with throw an error.

Using parameter in stored procedure to get dynamic table name

I already wrote a pretty complex stored procedure, but now i want to bring some dynamics into the procedures using variables. I still call myself a newbiew when it comes to sql programming, so i might be totally on the wrong way with what i'd like to achieve.
I am running the latest MySQL server 8.0.13 on windows (just for local dev).
My current idea for the stored procedure
... uses an input variable
... declares a cursor (using the var)
... create a temp table (using the var)
... iterates through the temp table
... write data to a new table
I think i understand some of the basic tools to do that but i fail again and again with handling the variable(s)
The following code shows the top part of the project where i already fail.
PROCEDURE sprProcedure (
IN vInputParameter varchar(64)
)
BEGIN
DECLARE vFinished INTEGER DEFAULT 0;
-- declare cursor
DECLARE cCursor CURSOR FOR SELECT * FROM tbltmp_(vInputParameter);
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET vFinished = 1;
-- drop / create temp table
DROP TABLE IF EXISTS (vInputParameter);
CREATE TEMPORARY TABLE tbltmp_(vInputParameter)
SELECT * FROM `tbl_DataSource`;
... did not paste any further code as i can't deal with the following issue.
I tried
... using the variable directly > variable is not resolved in DECLARE CURSOR statement
... define user-defined variable before local-variables is not allowed
... CONCAT'ed the string to build a statement and EXECUTE'ed it > does not work in the DECLAREpart of the stored procedure
At this point i am totally open to every hint or totally new ideas about how to approach this.
Thanks for any advice!
[Update]
My approach up there has some flaws and i did not understand the basic concept of temp tables for example being unique to the session. Thanks to 'D's Query' and a little more reading i now have a working stored procedure without having to deal with dynamic names of cursors and temp tables.
I dont know what actually you are focusing on but loading a dynamic tables can be possible with prepared statements in Stored Procedures but prepared statements won't work with CURSORS.
Example of Prepared statement is
SET $sql=CONCAT('SELECT * from ', var_tablename);
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

MySQL Load Data Infile when conditions are met

I am currently building a MySQL database. The database is storing data which is being supplied by another organisation and the format of the files we recieve is, shall we say, somewhat inconsistent.
I have writted a function which assess the file based on some simple rules and returns a message saying 'file ok' or else one of a list of hard coded error messages. The way I would like to use this function would be to say something like:
if check_10m_file() = 'file ok' then
load data infile '\\\\server\\filepath\file.csv'
fields terminated by ','
...(etc)
My problem is that the if..then..else control structure does not seem to be allowed outside of stored procedures and the load data infile command is not allowed inside stored procedures.
I have attempted to trick my way around this by building the load data infile statement as a prepared statement but then I get an error
"This command is not supported in the prepared statement protocol yet"
So my question is, does anyone know of a way in which I can run a load data statement only when conditions are met? I would ideally like to put this into a stored procedure but if I could just save the code as a script to run later, that would be acceptable.
One option is to use UDF, for example: lib_mysqludf_sys.
After installing the UDF, you can do something like:
Shell script (/server/loadpath/load.sh):
mysql -u [user] -p[pass] -e "LOAD DATA INFILE '$1' INTO TABLE $2;"
Stored Procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS load_data$$
CREATE PROCEDURE load_data(pfile VARCHAR(100), pdbtable VARCHAR(100))
BEGIN
DECLARE exec_str VARCHAR(500);
DECLARE ret_val INT;
IF (check_10m_file() = 'file ok') THEN
SET exec_str := CONCAT('sh /server/loadpath/load.sh ', pfile, ' ', pdbtable);
SET ret_val := sys_exec(exec_str);
IF ret_val = 0 THEN
SELECT 'OK' Result;
ELSE
SELECT 'ERROR' Result;
END IF;
END IF;
END$$
DELIMITER ;
CALL load_data('/server/filepath/file.csv', 'mydb.mytable');
IMPORTANT: Validate the input data to prevent any code injection.

Suppose I want to create a "stored function" for MYSQL. Where do I wrote it? Which file?

Of course, I could go into mysql console and type the Function. But what if I want to store it for future use? What do I do?
Most projects have an SQL file to initialize the database from scratch. This way, one can set up the application database by simply running this SQL file. Your CREATE PROCEDURE/FUNCTION query would also go in this file.
There's a good tutorial here:
http://www.databasejournal.com/features/mysql/article.php/3525581/MySQL-Stored-Procedures-Part-1.htm
You need to use stored procedures. Once written, these are stored in the database along with your tables. They can be invoked using the CALL <procedure> statement.
Here's an example procedure that populates table1 with random values:
DELIMITER //
DROP PROCEDURE IF EXISTS autofill//
CREATE PROCEDURE autofill()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 20000 DO
INSERT INTO table1 (size) VALUES (FLOOR((RAND() * 1000)));
SET i = i + 1;
END WHILE;
END;
//
DELIMITER ;
Once the procedure has been written, it is called like this:
CALL autofill();

How to use Mysql variables with Hibernate?

I need to use a native sql query in Hibernate with use of variable.
But hibernate throws an error saying: Space is not allowed after parameter prefix
So there is a conflict with the := mysql variable assignment and hibernate variable assignment.
Here is my sql query:
SET #rank:=0;
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;
the hibernate code (jpa syntax):
Query query = em.createNativeQuery(theQuery);
query.executeUpdate();
I can't use a stored procedure because my sql query is dynamically generated ('Level' can be 'int' or 'force'...)
How can I do this ?
thanks
Well, I finally use stored procedure (yes, what I don't want initially) to create dynamic query (I don't think it was possible).
Here is my code:
The stored procedure:
DELIMITER |
DROP PROCEDURE IF EXISTS UpdateRank |
CREATE PROCEDURE UpdateRank(IN shortcut varchar(30))
BEGIN
SET #rank=0;
SET #query=CONCAT('UPDATE Rank SET ', shortcut, '=#rank:=#rank+1 ORDER BY ', shortcut);
PREPARE q1 FROM #query;
EXECUTE q1;
DEALLOCATE PREPARE q1;
END;
|
DELIMITER ;
The tip is the use of the CONCAT function to dynamically create a query in the stored procedure.
Then, call the procedure in classic hibernate function:
Query q = em.createNativeQuery("CALL updateRank('lvl')");
q.executeUpdate();
I'll copy paste my answer from https://stackoverflow.com/a/25552002/3987202
Another solution for those of us who can't make the jump to Hibernate 4.1.3.
Simply use /*'*/:=/*'*/ inside the query. Hibernate code treats everything between ' as a string (ignores it). MySQL on the other hand will ignore everything inside a blockquote and will evaluate the whole expression to an assignement operator.
I know it's quick and dirty, but it get's the job done without stored procedures, interceptors etc.
Use MySQL Proxy to rewrite the query after Hibernate has sent the query to the database.
For example supply Hibernate with this,
UPDATE Rank SET rank_Level=incr(#rank) ORDER BY Level;
but rewrite it to this,
UPDATE Rank SET rank_Level=#rank:=#rank+1 ORDER BY Level;