I appreciate your answer. I changed the procedure with your changes, but I've done something wrong. Would you please tell me what is wrong with the code?
So I'll need to include the code at the end of the main question.
Attempt #2 is at the bottom.
Can someone tell me what is wrong with this procedure? The system tells me there is an error at:
DECLARE myemail_cursor CURSOR FOR
USE v_db; SELECT DISTINCT u.mail FROM users u INNER JOIN users_roles ur ON u.uid=ur.uid INNER JOIN role r ON ur.rid=r.rid WHERE r.name = 'court administrator' AND from_unixtime(u.access) >= NOW() - INTERVAL 1 YEAR;
If I run USE mydb; SELECT...in a query it works fine. Can I not use 'USE variable; select...' in a procedure?
BEGIN
DECLARE v_finished, v_finished1 BOOLEAN DEFAULT FALSE;
DECLARE v_email varchar(4000) DEFAULT "";
DECLARE v_db varchar(400) DEFAULT "";
DECLARE mydb_cursor CURSOR FOR
SELECT TABLE_SCHEMA AS 'database' FROM information_schema.TABLES WHERE TABLE_TYPE = 'BASE TABLE' and table_name='users';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = TRUE;
open mydb_cursor;
get_mydb: LOOP
FETCH FROM mydb_cursor INTO v_db;
IF v_finished THEN
CLOSE mydb_cursor;
LEAVE get_mydb;
END IF;
DECLARE myemail_cursor CURSOR FOR
USE v_db; SELECT DISTINCT u.mail FROM users u INNER JOIN users_roles ur ON u.uid=ur.uid INNER JOIN role r ON ur.rid=r.rid WHERE r.name = 'court administrator' AND from_unixtime(u.access) >= NOW() - INTERVAL 1 YEAR;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished1 = TRUE;
OPEN myemail_cursor;
get_myemail: LOOP
FETCH FROM myemail_cursor INTO v_email';
IF v_finished1 THEN
CLOSE myemail_cursor;
SET v_finished1 = FALSE;
LEAVE get_myemail;
END IF;
-- build email list
SET email_list = CONCAT(v_email," ",email_list);
END LOOP get_myemail;
CLOSE myemail_cursor;
END LOOP get_email;
CLOSE email_cursor;
END LOOP get_mydb;
END
Attempt #2.
I am getting this error: table 'v_db.users' doesn't exist
The first cursor only selects DBs where the table users exists, so I can't figure out why I"m getting the error.
BEGIN
DECLARE v_finished, v_finished1 BOOLEAN DEFAULT FALSE;
DECLARE v_email varchar(4000) DEFAULT "";
DECLARE v_db varchar(400) DEFAULT "";
DECLARE mydb_cursor CURSOR FOR
SELECT TABLE_SCHEMA AS 'database' FROM information_schema.TABLES WHERE TABLE_TYPE = 'BASE TABLE' and table_name='users';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = TRUE;
open mydb_cursor;
get_mydb: LOOP
FETCH FROM mydb_cursor INTO v_db;
IF v_finished THEN CLOSE mydb_cursor;
LEAVE get_mydb;
END IF;
BLOCK2: BEGIN
DECLARE myemail_cursor CURSOR FOR
SELECT DISTINCT u.mail FROM v_db.users u INNER JOIN v_db.users_roles ur ON u.uid=ur.uid INNER JOIN v_db.role r ON ur.rid=r.rid WHERE r.name = 'court administrator' AND from_unixtime(u.access) >= NOW() - INTERVAL 1 YEAR;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished1 = TRUE;
OPEN myemail_cursor;
get_myemail: LOOP
FETCH FROM myemail_cursor INTO v_email;
IF v_finished1 THEN
CLOSE myemail_cursor;
LEAVE get_myemail;
END IF;
SET email_list = CONCAT(v_email," ",email_list);
END LOOP get_myemail;
END BLOCK2;
END LOOP get_mydb;
END
23.2.1 Stored Routine Syntax
...
When the routine is invoked, an implicit USE db_name is performed (and undone when the routine terminates). USE statements within stored routines are not permitted.
...
Try:
...
DECLARE mydb_cursor CURSOR FOR
SELECT
DISTINCT u.mail
FROM
v_db.users u
INNER JOIN v_db.users_roles ur ON u.uid=ur.uid
INNER JOIN v_db.role r ON ur.rid=r.rid
WHERE
r.name = 'court administrator' AND
from_unixtime(u.access) >= NOW() - INTERVAL 1 YEAR;
...
Remember:
13.6.3 DECLARE Syntax
...
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other
statements.
...
Related
I am trying to create a repetition in 'cursor' that uses 'join', but it doesn't work.
Already tested without 'join' and works normally.
My code:
DECLARE hvDataAtual DATE;
DECLARE manDataAtual DATETIME;
DECLARE motCodAtual INT;
DECLARE done INT DEFAULT FALSE;
DECLARE Crs_vei_man
CURSOR FOR (
SELECT hvedatageracao, hvedatageracao, hvemotorista
FROM tableone INNER JOIN tabletwo ON hveveiculo = manveiculo
WHERE SUBSTRING(mandata, 1, 10) = SUBSTRING(hvedatageracao, 1, 10) LIMIT 10);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN Crs_vei_man;
myloop: LOOP
FETCH Crs_vei_man
INTO hvDataAtual,
manDataAtual,
motCodAtual;
-- Insert 1 row (null, null, null) ?
INSERT INTO testes VALUES(hvDataAtual, manDataAtual, motCodAtual);
IF done THEN
LEAVE myloop;
END IF;
IF motCodAtual > 0 THEN
INSERT INTO testes VALUES('hvDataAtual', 'manDataAtual', 'motCodAtual');
END IF;
END LOOP;
CLOSE Crs_vei_man;
This code is in a stored procedure.
What is happening?
I am trying to use nested loop outer one to access all categories then using that taxID I am querying posts from that tax so that I can assign them ranking as per their category placement.
But I am facing problem that the inner loop "RankingLoop " is only accessing all post results of one taxID then terminate loop and don't loop for other category post if I use Repeat in place of RankingLoop then first record of each taxID loop become accessible. can any body please help to explain problem in my code?
Thank you for help in advance.
DELIMITER $$
CREATE PROCEDURE Catranking__()
Begin
Declare txID INT; Declare txmaxcount INT;
Declare txCount CURSOR FOR SELECT max(term_taxonomy_id) FROM `wp_term_taxonomy` where taxonomy = 'category' and count > 0;
Declare taxonomyIDS CURSOR FOR SELECT term_taxonomy_id FROM `wp_term_taxonomy` where taxonomy = 'category' and count > 0;
open taxonomyIDS; open txCount;
FETCH txCount into txmaxcount;
loop_label: LOOP
FETCH taxonomyIDS into txID;
if txID < (txmaxcount+1) then set #rank=0;
categorywisePostSorting: begin
DECLARE Vranking INT;
DECLARE VPOSTID INT;
Declare RankingArray CURSOR FOR select #rank:=#rank+1 as ranking, POSTID FROM RankingView WHERE term_id = txID order by claimedProducts desc, commentcount desc, pageviews desc;
open RankingArray;
RankingLoop : Loop
FETCH RankingArray into Vranking, VPOSTID;
select VPOSTID;
end Loop RankingLoop;
close RankingArray;
END categorywisePostSorting;
end if;
END LOOP loop_label;
close taxonomyIDS; close txCount;
END$$
DELIMITER ;
Since there are unknown logic, modified as below,
DELIMITER $$
CREATE PROCEDURE Catranking__()
BEGIN
DECLARE txmaxcount INT;
DECLARE txID INT;
DECLARE done1 BOOLEAN DEFAULT FALSE;
# assuming `count` is column name so instead of cursor we can use a local var
#Declare txCount CURSOR FOR SELECT max(term_taxonomy_id) FROM `wp_term_taxonomy` where taxonomy = 'category' and count > 0; -- "count" is illegal here(whether its column name or count(*))... so check from ur side
DECLARE taxonomyIDS CURSOR FOR SELECT term_taxonomy_id FROM `wp_term_taxonomy` WHERE taxonomy = 'category' AND count > 0; -- same count issue
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1=TRUE;
SELECT
MAX(term_taxonomy_id)
INTO txmaxcount FROM
`wp_term_taxonomy`
WHERE
taxonomy = 'category' AND `count` > 0;
OPEN taxonomyIDS;
TAXONOMYIDS_LOOP: LOOP
FETCH taxonomyIDS INTO txID;
IF done1 THEN
LEAVE TAXONOMYIDS_LOOP;
END IF;
IF txID < (txmaxcount+1) THEN
SET #rank=0;
CATEGORYWISEPOSTSORTING: BEGIN
DECLARE Vranking INT; -- why this var? hasn't used in the code
DECLARE VPOSTID INT;
DECLARE done2 BOOLEAN DEFAULT FALSE;
DECLARE RankingArray CURSOR FOR
SELECT #rank:=#rank+1 AS ranking, POSTID FROM RankingView WHERE term_id = txID ORDER BY claimedProducts DESC, commentcount DESC, pageviews DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=TRUE;
OPEN RankingArray;
RANKINGLOOP : LOOP
FETCH RankingArray INTO Vranking, VPOSTID;
IF done2 THEN
LEAVE RANKINGLOOP;
END IF;
SELECT VPOSTID;
END LOOP RANKINGLOOP;
CLOSE RankingArray;
SET done2= FALSE;
END CATEGORYWISEPOSTSORTING;
END IF;
END LOOP TAXONOMYIDS_LOOP;
CLOSE taxonomyIDS;
SET done=FALSE;
END$$
DELIMITER ;
I normally try to figure things out on my own, but I'm stumped on this.
I have leads in one SugarCRM account that I want to reassign a specific number to each active user. Every time I try to run this I keep getting "ERROR 1064 (42000):... at Line 4" and I have no idea what is wrong.
This is what I have made so far:
Hello, I normally try to figure things out on my own, but I'm stumped on this.
I have leads in one SugarCRM account that I want to reassign a specific number to each active user. Every time I try to run this I keep getting "ERROR 1064 (42000):... at Line 4" and I have no idea what is wrong.
DELIMITER $$
DROP PROCEDURE IF EXISTS assign_leads $$
CREATE PROCEDURE assign_leads(num_rows INT)
BEGIN
SET num_rows = num_rows;
DECLARE i VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE employee_cursor CURSOR FOR
SELECT users.id
FROM users
WHERE (((users.title)="South Carolina Qualifier") AND ((users.status)="Active"));
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN employee_cursor;
employee_loop: LOOP
FETCH employee_cursor INTO i;
SET #sql_text1 = concat('UPDATE leads SET assigned_user_id = ',#i,' WHERE ((assigned_user_id IS NULL OR assigned_user_id = '1' OR assigned_user_id = '') AND do_not_call = '0' AND deleted = '0' AND status = 'New') LIMIT ',#num_rows,' 1;')
PREPARE stmt1 FROM #sql_text1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
IF exit_loop THEN
CLOSE employee_cursor;
LEAVE employee_loop;
END IF;
END LOOP employee_loop;
END $$
DELIMITER ;
Some considerations:
SET must be located after the DECLARE:
...
CREATE PROCEDURE assign_leads(num_rows INT)
BEGIN
-- SET num_rows = num_rows;
DECLARE i VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE employee_cursor CURSOR FOR
SELECT users.id
FROM users
WHERE (((users.title)="South Carolina Qualifier") AND ((users.status)="Active"));
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
SET num_rows = num_rows;
OPEN employee_cursor;
...
This assignment (SET) does not make much sense, it assigns the value of num_rows parameter to the same num_rows parameter.
Must escape some characters from your #sql_text1 variable and add ; at the end of the statement:
...
/*
SET #sql_text1 = concat('
UPDATE leads SET assigned_user_id = ',#i,'
WHERE (
(assigned_user_id IS NULL OR assigned_user_id = '1' OR assigned_user_id = '') AND
do_not_call = '0' AND deleted = '0' AND status = 'New'
)
LIMIT ',#num_rows,' 1;
')
*/
SET #sql_text1 = concat('
UPDATE leads SET assigned_user_id = ',#i,'
WHERE (
(assigned_user_id IS NULL OR assigned_user_id = \'1\' OR assigned_user_id = \'\') AND
do_not_call = \'0\' AND deleted = \'0\' AND status = \'New\'
)
LIMIT ',#num_rows,' 1;
');
...
#i and #num_rows are 9.4. User-Defined Variables, i is one 13.6.4.1. Local Variable DECLARE Syntax and num_rows is a routine parameter, are different variables.
This is the query...
DELIMITER $$
DROP PROCEDURE IF EXISTS assign_leads $$
CREATE PROCEDURE assign_leads(num_rows INT)
BEGIN
DECLARE i VARCHAR(255);
DECLARE exit_loop BOOLEAN;
DECLARE employee_cursor CURSOR FOR
SELECT users.id
FROM users
WHERE (((users.title)="South Carolina Qualifier") AND((users.status)="Active"));
DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;
OPEN employee_cursor;
employee_loop: LOOP
FETCH employee_cursor INTO i;
SET #sql_text1 = concat('
UPDATE leads SET assigned_user_id = ',#i,'
WHERE (
(assigned_user_id IS NULL OR assigned_user_id = \'1\' OR assigned_user_id = \'\') AND
do_not_call = \'0\' AND deleted = \'0\' AND status = \'New\'
) LIMIT ',#num_rows,' 1;'
);
PREPARE stmt1 FROM #sql_text1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
IF exit_loop THEN
CLOSE employee_cursor;
LEAVE employee_loop;
END IF;
END LOOP employee_loop;
END $$
DELIMITER ;enter code here
I have a stored procedure like the following. There is an error showing at the update statement before the cursor declaration. When I remove the cursor statement, the stored procedure works fine. Why can't be there an update statement before the cursor statement?
DROP PROCEDURE IF EXISTS GenerateAlert;
DELIMITER $$
CREATE PROCEDURE GenerateAlert()
BEGIN
DECLARE done INTEGER DEFAULT FALSE;
DECLARE temp_project_id INT DEFAULT 0;
DECLARE temp_finish_time DATETIME DEFAULT NOW();
DECLARE _message_class INT DEFAULT 3;
DECLARE proj_user_id INT DEFAULT 0;
-- get message text template
DECLARE message_template VARCHAR(255) DEFAULT
(
SELECT alert_message_template FROM alerts WHERE id = 6
);
-- get maximum allowed minutes
DECLARE allowed_time INT DEFAULT
(
SELECT alert_value_1 FROM alerts WHERE id = 4
);
-- flag all messages with class 3 to deleted = true
UPDATE messages
SET is_deleted = 1
WHERE messages_class = 3;
DECLARE _cur CURSOR FOR
SELECT d.project_id, MAX(finish_time)
FROM
client_docs AS d INNER JOIN
issues AS i ON d.project_id = i.project_id INNER JOIN
working_times AS t ON i.id = t.issue_id
WHERE
d.status = 1 AND
t.finish_time IS NOT NULL AND
t.category = 1
GROUP BY d.project_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO temp_project_id, temp_finish_time;
IF done THEN
LEAVE read_loop;
END IF;
-- add more minutes to finish time
SET temp_finish_time = DATE_ADD(temp_finish_time, INTERVAL allowed_time MINUTE);
IF temp_finish_time < NOW() THEN
-- this project must be alerted
-- get project user
SELECT c.staff INTO proj_user_id
FROM
projects AS p INNER JOIN
clients AS c ON p.client_id = c.id
WHERE
p.id = temp_project_id;
END IF;
END LOOP read_loop;
CLOSE _cur;
END
$$
DELIMITER ;
Found the answer: The declaration statments must come before any other transactional statement in MySQL stored procedure.
SQL, missing end, but why? Second comment in the answer.
I have the following bunch of code trying to update a field using 2 cursors the one inside the other. I use the first cursor just to get an id value (1st cursor) and then I get a list of other id values based on that id (2nd cursor). The problem is that the result set from the 2nd cursor contains the last id twice! I can't find the bug! Something in the loop, something in the termination variable for the 2 cursors?
Any help more than welcome! Thanks in advance!
DELIMITER $$
DROP PROCEDURE IF EXISTS updateNumberOfPoisForPlacesWithChildren$$
CREATE PROCEDURE updateNumberOfPoisForPlacesWithChildren()
BEGIN
DECLARE single_place_id INT(11);
DECLARE single_unique_parents_id INT(11);
DECLARE done, temp_number_of_pois, sum_number_of_pois INT DEFAULT 0;
DECLARE unique_parents_ids CURSOR FOR SELECT DISTINCT `parent_id` FROM `places` WHERE `parent_id` IS NOT NULL;
DECLARE temp_places_ids CURSOR FOR SELECT `id` FROM `places` WHERE `parent_id` = single_unique_parents_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN unique_parents_ids;
main_loop_for_parent_ids : LOOP
SET sum_number_of_pois = 0;
IF done = 1 THEN
CLOSE unique_parents_ids;
LEAVE main_loop_for_parent_ids;
END IF;
IF NOT done = 1 THEN
FETCH unique_parents_ids INTO single_unique_parents_id;
OPEN temp_places_ids;
main_loop_for_places : LOOP
IF done = 1 THEN
CLOSE temp_places_ids;
LEAVE main_loop_for_places;
END IF;
IF NOT done = 1 THEN
FETCH temp_places_ids INTO single_place_id;
SELECT COUNT(`id`) INTO temp_number_of_pois FROM `pois` WHERE `place_id` = single_place_id;
SET sum_number_of_pois = sum_number_of_pois + temp_number_of_pois;
END IF;
END LOOP;
UPDATE `places` SET `number_of_pois`=sum_number_of_pois WHERE `id` = single_unique_parents_id;
END IF;
END LOOP;
END$$
DELIMITER ;
I think your problem is about here...
IF NOT done = 1 THEN
FETCH temp_places_ids INTO single_place_id;
SELECT COUNT(`id`) INTO temp_number_of_pois FROM `pois` WHERE `place_id` = single_place_id;
SET sum_number_of_pois = sum_number_of_pois + temp_number_of_pois;
END IF;
The FETCH sets DONE to be 1 when it exhausts the result set, but you proceed because you've already passed the DONE test.
Perhaps...
FETCH temp_places_ids INTO single_place_id;
IF NOT done = 1 THEN
SELECT COUNT(`id`) INTO temp_number_of_pois FROM `pois` WHERE `place_id` = single_place_id;
SET sum_number_of_pois = sum_number_of_pois + temp_number_of_pois;
END IF;