I created a store procedure to do some insertions, fetch the records of a table and insert it into another table. For that I used cursor (my first use of cursor).
My script below:
CREATE DEFINER=`root`#`localhost` PROCEDURE `tenant_creation`(
IN admin_id int, tenant_name varchar(50),tenant_url varchar(50),
tenant_email varchar(50),tenant_phone varchar(50),first_name varchar(50),
last_name varchar(50),plan_id varchar(50),IN is_available tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
ROLLBACK;
END;
BEGIN
START TRANSACTION;
#insert Tenant details
Insert into tenant(admin_id,tenant_name,tenant_url,tenant_email,tenant_phone,first_name,last_name,plan_id, is_available)
values(admin_id,tenant_name,tenant_url,tenant_email,tenant_phone,first_name,last_name,plan_id,is_available);
SET #tenant_id = LAST_INSERT_ID();
#create Administrator Group
Insert into user_group(tenant_id,user_group_name,description)
values(#tenant_id,"Administrator","Default Administrator's Group");
SET #group_id = LAST_INSERT_ID();
#Create Default Tenan Admin User
Insert into users(tenant_id,username,`password`,firstname,lastname,email)
values(#tenant_id,"Administrator","$2y$10$AxTjqOxYk6atjDSO2Q4iQOprSvYMnR/jAboqfDYkvC1IG43Rwknw6","Default","Default",tenant_email);
#Attach the user to the group
Set #user_id = LAST_INSERT_ID();
Insert into user_group_relationship(tenant_id,user_group_id,user_id)
values(#tenant_id,#group_id,#user_id);
#create Admin profile
insert into profile(tenant_id,profile_name,description)
values(#tenant_id,"Administrator","Administrator Profile");
#Attach the Admin group to the profile
Set #profile_id = LAST_INSERT_ID();
Insert into profile_group_relationship(tenant_id,group_id,profile_id)
values(#tenant_id,#group_id,#profile_id);
END;
BEGIN
#bind the profile to the available screens
#1 fetch all the modules in system
DECLARE cur CURSOR FOR Select system_screen.screen_id,system_screen.screen_name,module_screen_relationship.module_id
from system_screen
join module_screen_relationship
on module_screen_relationship.screen_id = system_screen.screen_id;
begin
DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
#Fetch one record from CURSOR and set to some variable(If not found then done will be set to 1 by continue handler)
FETCH cur INTO c_screen_id,c_screen_name,c_module_id;
#If done set to 1 then exit the loop else continue
IF done THEN
LEAVE read_loop;
END IF;
Insert into profile_screen_relationship(tenant_id,profile_id,screen_id,module_id,access_level)
values(#tenant_id,#profile_id,c_screen_id,c_module_id,4);
END LOOP read_loop;
#Closing the cursor
CLOSE cur;
End;
COMMIT;
END;
END
but I only got "Error 1327: Undeclared variable: c_screen_id".
What do you think I am doing wrong?
I believe that you have to declare the variables at the beggining as the official documentation shows:
http://dev.mysql.com/doc/refman/5.7/en/cursors.html
DECLARE a CHAR(16);
DECLARE b, c INT;
....
FETCH cur1 INTO a, b;
FETCH cur2 INTO c;
Related
I am trying to implement a trigger which transfers multiple records from 4 different tables to another set of 4 tables (denoted by the _history suffix) which have the same schema.
The trigger is as follows
DELIMITER //
create trigger shift_to_history
before update on event_ledger
for each row
begin
declare id,event_id,communication_number,communication_flag,slot_number,room_id,status_level,prev_status_level int default 0;
declare msg text;
declare req_date,end_date,start_date date;
declare purpose varchar(30);
declare misc_ledger_cursor cursor for select * from misc_ledger where event_id = old.event_id;
declare resource_communication_cursor cursor for select * from resource_communication where event_id = old.event_id;
declare slots_and_details_cursor cursor for select * from slots_and_details where event_id = old.event_id;
declare event_communication_cursor cursor for select * from event_communication where event_id = old.event_id;
insert into event_ledger_history values(old.event_id,old.event_name,old.description,old.username,old.start_date,old.end_date);
open misc_ledger_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
misc_ledger_transfer: loop
fetch misc_ledger_cursor into event_id,communication_number,req_date,msg,communication_flag;
if finished = 1 then
leave misc_ledger_transfer;
end if;
insert into misc_ledger_history values (event_id,communication_number,req_date,msg,communication_flag);
end loop misc_ledger_transfer;
end;
close misc_ledger_cursor;
delete from misc_ledger where event_id = old.event_id;
open resource_communication_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
resource_coms_transfer: loop
fetch resource_communication_cursor into event_id,msg,communication_number,communication_flag;
if finished = 1 then
leave resource_coms_transfer;
end if;
insert into resource_communication_history values (event_id,msg,communication_number,communication_flag);
delete from resource_communication where id = event_id;
end loop resource_coms_transfer;
end;
close resource_communication_cursor;
open event_communication_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
event_coms_transfer: loop
fetch event_communication_cursor into event_id,msg,communication_number,communication_flag;
if finished = 1 then
leave event_coms_transfer;
end if;
insert into event_communication_history values (event_id,msg,communication_number,communication_flag);
end loop event_coms_transfer;
end;
close event_communication_cursor;
delete from event_communication where event_id = old.event_id;
open slots_and_details_cursor;
begin
declare finished int default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
slots_and_details_transfer: loop
fetch slots_and_details_cursor into id,event_id,slot_number,room_id,start_date,end_date,status_level,prev_status_level,purpose,msg;
if finished = 1 then
leave slots_and_details_transfer;
end if;
insert into slots_and_details_history values (id,event_id,slot_number,room_id,start_date,end_date,status_level,prev_status_level,purpose,msg);
end loop slots_and_details_transfer;
end;
close slots_and_details_cursor;
delete from slots_and_details where event_id = old.event_id;
end//
DELIMITER ;
The Trigger runs only till
insert into event_ledger_history values(old.event_id,old.event_name,old.description,old.username,old.start_date,old.end_date);
After which it does not do anything.The MySQL Terminal gives a success message but the desired output is not achieved. ie The remaining history tables are till empty (the ones which use the cursor).
I reffered to MySQL stored procedure, handling multiple cursors and query results but did not receive favorable results.
I have a stored procedure snippet like this
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id varchar(100) DEFAULT "";
DECLARE cursor1 CURSOR for select id from t1 where name like 's%';
OPEN cursor1;
get_t1: LOOP
FETCH cursor1 into c_id;
p:begin
declare cursor2 cursor for select id from t2 where cl_id=c_id;
open cursor2;
get_t2: loop
fetch project_cursor into p_id;
// perform some tasks
t:begin
declare cursor3 cursor for select id from t3 where pr_id=p_id;
open cursor3;
get_t3:loop
fetch cursor3 into t_id;
IF v_finished = 1 THEN
LEAVE get_t3;
END IF;
//perform some tasks
close cursor3;
select p_id;
end t;
end loop t2;
end p;
END LOOP t1;
END
here select statement is not displaying any data
when i write select under cursor 3 it is working.
did i made any mistake? anything I missed
Some basic logic has been added in your SP, Try it whether this is what you are expecting.
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id VARCHAR(100) DEFAULT "";
DECLARE done1 BOOLEAN DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR SELECT id FROM t1 WHERE name LIKE 's%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1=TRUE;
OPEN cursor1;
GET_T1: LOOP
FETCH cursor1 INTO c_id;
IF done1 THEN
LEAVE GET_T1;
END IF;
P:BEGIN
DECLARE p_id INT ; -- check which data types suits you, might be int
DECLARE done2 BOOLEAN DEFAULT FALSE;
DECLARE cursor2 CURSOR FOR SELECT id FROM t2 WHERE cl_id=c_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=TRUE;
OPEN cursor2;
GET_T2: LOOP
FETCH cursor2 INTO p_id;
IF done2 THEN
LEAVE GET_T2;
END IF;
/* perform some task */
T:BEGIN
DECLARE t_id INT ; -- check which data types suits you, might be int
DECLARE done3 BOOLEAN DEFAULT FALSE;
DECLARE cursor3 CURSOR FOR SELECT id FROM t3 WHERE pr_id=p_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done3=TRUE;
OPEN cursor3;
GET_T3:LOOP
FETCH cursor3 INTO t_id;
IF done3 THEN
LEAVE GET_T3;
END IF;
/* perform some tasks */
#select p_id; -- don't know what you are doing with this
END LOOP GET_T3;
CLOSE cursor3;
SET done3=FALSE;
END T;
END LOOP GET_T2;
CLOSE cursor2;
SET done2= FALSE;
END P;
END LOOP GET_T1;
CLOSE cursor1;
SET done1= FALSE;
END
Why both my variables output NULL? SELECT part of the cursor is working properly.
CREATE PROCEDURE p2()
BEGIN
# Account table
DECLARE accountid INT;
DECLARE accountname VARCHAR(1000);
# 1. cursor finished/done variable comes first
DECLARE done INT DEFAULT 0;
# 2. the curser declaration and select
DECLARE c_account_id_name CURSOR FOR SELECT
accountid,
accountname
FROM temp.test;
# 3. the continue handler is defined last
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
OPEN c_account_id_name;
SET accountid = 0;
SET accountname = '';
read_loop: LOOP
FETCH c_account_id_name
INTO accountid, accountname;
IF done
THEN
LEAVE read_loop;
END IF;
SELECT accountname;
END LOOP;
END;
Variable and select attribute in cursor can't be the same...it's a MySQL bug.
This will work
DROP PROCEDURE IF EXISTS p2;
DELIMITER $$
CREATE PROCEDURE p2()
BEGIN
# Account table
DECLARE v_accountidsome INT; #pay attention
DECLARE v_accountnameelst VARCHAR(1000); #pay attention
# 1. cursor finished/done variable comes first
DECLARE v_done INT DEFAULT FALSE;
# 2. the cursor declaration and select
DECLARE c_account_id_name CURSOR FOR SELECT
accountid, #pay attention
accountname #pay attention
FROM temp.test;
# 3. the continue handler is defined last
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET v_done = TRUE;
OPEN c_account_id_name;
read_loop: LOOP
FETCH c_account_id_name
INTO v_accountidsome, v_accountnameelst;
IF v_done
THEN
LEAVE read_loop;
END IF;
SELECT v_accountidsome;
SELECT v_accountnameelst;
END LOOP;
CLOSE c_account_id_name;
END $$
DELIMITER ;
CALL p2();
Find more here
This is my current trigger:
DELIMITER $$
CREATE DEFINER=`root`#`127.0.0.1` TRIGGER `unique_visit_new_campaign` AFTER INSERT ON `unique_visit` FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE pixel_id int;
DECLARE campaign_id varchar(45);
DECLARE cur CURSOR FOR SELECT id FROM pixels;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO pixel_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT IGNORE INTO pixels_campaign (campaign_id , pixel_id , date) VALUES (NEW.campaign_id ,pixel_id, current_timestamp);
END LOOP;
CLOSE cur;
END
I need it to NOT TRIGGER when new.campaign_id is empty or equals to the string {campaign_id}
I tried using MySQL IF but with no success.
Also, It kinda auto increment even when there is a campaign id already (when it ignores). any way I can stop that from happening?
Did you try this?
DELIMITER $$
CREATE DEFINER=`root`#`127.0.0.1` TRIGGER `unique_visit_new_campaign` AFTER INSERT ON `unique_visit` FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE pixel_id int;
DECLARE campaign_id varchar(45);
DECLARE cur CURSOR FOR SELECT id FROM pixels;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
IF new.campaign = '' or new.campaign = '{campaign_id}' or new.campaign is null THEN
OPEN cur;
ins_loop: LOOP
FETCH cur INTO pixel_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT IGNORE INTO pixels_campaign (campaign_id , pixel_id , date) VALUES (NEW.campaign_id ,pixel_id, current_timestamp);
END LOOP;
CLOSE cur;
END IF
END
I'm getting "ERROR 1415 (0A000): Not allowed to return a result set from a trigger" when updating a table containing the following trigger, but don't understand why.
CREATE TRIGGER my_trigger AFTER UPDATE ON my_triggering_table
FOR EACH ROW CALL my_procedure();
I'm away that triggers cannot use a SELECT which returns a result set, but the called procedure (and its children) use only CURSOR FOR SELECT and FETCH INTO which, I understand, is permitted. They read, but do not modify, the triggering table.
Can anyone explain the error? (MySQL 5.5) The called procedures below.
CREATE PROCEDURE my_procedure()
BEGIN
DECLARE v_mark VARCHAR(4);
DECLARE v_lat, v_lon DOUBLE;
DECLARE eof INT DEFAULT FALSE;
DECLARE my_cursor CURSOR FOR SELECT `mark`, `lat`, `lon` FROM my_triggering_table ORDER BY `order`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = TRUE;
DELETE FROM my_output_table;
OPEN my_cursor;
loop1: LOOP
FETCH my_cursor INTO v_mark, v_lat, v_lon;
IF eof THEN
LEAVE loop1;
END IF;
CALL my_procedure_2(v_mark, v_lat, v_lon);
END LOOP;
CLOSE my_cursor;
END//
CREATE PROCEDURE my_procedure_2(IN from_mark VARCHAR(4), IN from_lat DOUBLE, IN from_lon DOUBLE)
BEGIN
DECLARE v_mark VARCHAR(4);
DECLARE v_lat, v_lon DOUBLE;
DECLARE eof INT DEFAULT FALSE;
DECLARE my_cursor CURSOR FOR SELECT `mark`, `lat`, `lon` FROM my_triggering_table ORDER BY `order`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET eof = TRUE;
OPEN my_cursor;
loop1: LOOP
FETCH my_cursor INTO v_mark, v_lat, v_lon;
IF eof THEN
LEAVE loop1;
END IF;
INSERT INTO my_output_table(`from`, `to`, `dist`, `brg`, `lat`, `lon`)
VALUES(from_mark
, v_mark
, IF(from_mark = v_mark, NULL, getDist(from_lat, from_lon, v_lat, v_lon))
, IF(from_mark = v_mark, NULL, getBearing(from_lat, from_lon, v_lat, v_lon))
, coord_dec2ms(from_lat, true)
, coord_dec2ms(from_lon, false)
);
END LOOP;
CLOSE my_cursor;
END//
The UDFs called do not reference any tables.