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.
Related
I have a procedure that returns multiple rows, but separately. Please take a look at its result:
I causes some issues when I want to fetch the result in the code (backend side). Now I want to create a temporary table and insert all rows inside it and then return that temp table as the result of the stored procedure. How can I do that inside procedure?
Not sure it above idea is a good idea .. that's the only thing I can probably be useful to merge all rows all in one table as SP's result.
Here is my current procedure:
DELIMITER $$
CREATE DEFINER=`administrator`#`localhost` PROCEDURE `lending_ewallets_balance_in_merchant`(IN `user_id_param` BIGINT UNSIGNED, IN `business_id_param` INT UNSIGNED)
NO SQL
BEGIN
DECLARE dossier_id INT;
DECLARE query_string VARCHAR(255) DEFAULT '';
DECLARE cursor_List_isdone BOOLEAN DEFAULT FALSE;
DECLARE user_dossiers CURSOR FOR
Select ld.id, lwp.query_string
FROM lending_users_dossiers ld
JOIN lending_where_to_pays lwp ON ld.lending_where_to_pay_id = lwp.id
WHERE user_id = user_id_param
AND (ld.status = 'activated' OR ld.status = 'finished');
# 'finished' is for loans
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_List_isdone = TRUE;
Open user_dossiers;
loop_List: LOOP
FETCH user_dossiers INTO dossier_id, query_string;
IF cursor_List_isdone THEN
LEAVE loop_List;
END IF;
SET #qry = CONCAT(
"SELECT ld.id lending_dossier_id, ld.type, SUM(let.credit) balance
FROM lending_users_dossiers ld
JOIN lending_ewallet_transactions let
ON ld.id = let.lending_dossier_id
WHERE ld.id = ", dossier_id,
" AND ", business_id_param, " IN(", query_string, ")",
"GROUP BY ld.id, ld.type");
PREPARE stmt FROM #qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP loop_List;
Close user_dossiers;
END$$
DELIMITER ;
Noted that, the MySQL version I use is MySQL v8.0.20.
The logic should be something like this. Outside the loop create a temp table if not exists and delete the data from it:
CREATE TEMPORARY TABLE
IF NOT EXISTS
user_dossiers_tmp (your columns);
DELETE FROM user_dossiers_tmp;
In your loop:
INSERT INTO user_dossiers_tmp VALUES (your data);
After your loop:
SELECT * FROM user_dossiers_tmp;
END$$
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$$
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;
I'm wrestling with MySQL stored procedures, and the PREPARE / EXECUTE statement pair. I'm attempting to run the (simplified) code below in order to create a stored procedure that will encapsulate several queries into a transaction with rollback. I continue to get
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 'goodID;
If I remove the transaction and handlers all is well with the code. If I remove the EXECUTEstatement the procedure can be created.
What am I missing here?
DELIMITER $$
USE `casc`$$
DROP PROCEDURE IF EXISTS `sp_T_MergeMemberIDs`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_T_MergeMemberIDs`(IN goodID VARCHAR(8), OUT param_sp_success TINYINT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;
START TRANSACTION;
SET param_sp_success = 0;
SET #SQL=
"SELECT * FROM member
WHERE memberID = ?";
PREPARE stmt FROM #SQL;
EXECUTE stmt USING goodID;
-- queries executed here using the same parameter
-- omitted for simplicity
SET param_sp_success = 1;
COMMIT;
END$$
As far as I remember, you need to use session user variable in execute ...using :
...
PREPARE stmt FROM #SQL;
SET #tmp_var = goodID;
EXECUTE stmt USING #tmp_var;
...
I would like to use LIMIT in a cursor. The cursor should be used and updated several times within a loop, each time with different parameters of LIMIT. Here some code:
DELIMITER $$
CREATE PROCEDURE `updateIt`() READS SQL DATA
BEGIN
declare done int(1) default 0;
declare counter int(10) default 0;
declare xabc int(10) default 0;
declare tab1Cursor cursor for select abc from tab1 limit 100000*counter, 100000;
declare continue handler for not found set done=1;
loopCounter: LOOP
set done = 0;
open tab1Cursor;
igmLoop: loop
fetch tab1Cursor into xabc;
if done = 1 then leave igmLoop; end if;
-- do something
end loop igmLoop;
close tab1Cursor;
if (counter = 1039)
leave loopCounter;
end if;
set counter = counter + 1;
END LOOP loopCounter;
END $$
DELIMITER ;
This, however, does not work (I also tried it with the cursor in the LOOP counterLoop). Can Mysql deal with dynamic cursors?
From the MySQL Manual
a cursor cannot be used for a dynamic statement that is prepared and
executed with PREPARE and EXECUTE. The statement for a cursor is
checked at cursor creation time, so the statement cannot be dynamic.
However there are 2 ways, according to this post in mysql forums:
The first is for cases where absolutely only one user at a time will be running the procedure. A prepare statement can be used to create a view with the dynamic SQL and the cursor can select from this statically-named view. There's almost no performance impact. Unfortunately, these views are also visible to other users (there's no such thing as a temporary view), so this won't work for multiple users.
Analogously, a temporary table can be created in the prepare statement and the cursor can select from the temporary table. Only the current session can see a temporary table, so the multiple user issue is resolved. But this solution can have significant performance impact since a temp table has to be created each time the proc runs.
Bottom line: We still need cursors to be able to be created dynamically!
Here's an example of using a view to pass the table name and column name into a cursor.
DELIMITER //
DROP PROCEDURE IF EXISTS test_prepare//
CREATE PROCEDURE test_prepare(IN tablename varchar(255), columnname varchar(50))
BEGIN
DECLARE cursor_end CONDITION FOR SQLSTATE '02000';
DECLARE v_column_val VARCHAR(50);
DECLARE done INT DEFAULT 0;
DECLARE cur_table CURSOR FOR SELECT * FROM test_prepare_vw;
DECLARE CONTINUE HANDLER FOR cursor_end SET done = 1;
SET #query = CONCAT('CREATE VIEW test_prepare_vw as select ', columnname, ' from ', tablename);
select #query;
PREPARE stmt from #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
OPEN cur_table;
FETCH cur_table INTO v_column_val;
WHILE done = 0 DO
SELECT v_column_val;
FETCH cur_table INTO v_column_val;
END WHILE;
CLOSE cur_table;
DROP VIEW test_prepare_vw;
END;
//
DELIMITER ;