i am copying data for a Many to Many Relationship table making a Third Table.
The stored procedure currently looks like this but it has some error
DELIMITER $$
CREATE PROCEDURE `test`.UpdateRelatedAccounts()
BEGIN
DECLARE ssn_sel_id VARCHAR(255) DEFAULT 0;
DECLARE id_sel_id CHAR(36) DEFAULT 0;
DECLARE id_sel_rel CHAR(36) DEFAULT 0;
DECLARE no_more_rows BOOLEAN;
DECLARE num_rows INT DEFAULT 0;
DECLARE no_more_rel_rows BOOLEAN;
DECLARE rel_num_rows INT DEFAULT 0;
DECLARE ssn_all_cur CURSOR FOR
SELECT ssn, id FROM ssn WHERE ssn NOT IN ('','000-00-0000');
DECLARE ssn_cur CURSOR FOR
SELECT id FROM ssn WHERE id != id_sel_id AND ssn = ssn_sel_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
-- DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rel_rows = TRUE;
OPEN ssn_all_cur;
SELECT FOUND_ROWS() INTO num_rows;
the_loop: LOOP
FETCH ssn_all_cur
INTO ssn_sel_id, id_sel_id;
IF no_more_rows THEN
CLOSE ssn_all_cur;
LEAVE the_loop;
END IF;
OPEN ssn_cur;
SELECT FOUND_ROWS() INTO rel_num_rows;
the_rel_loop: LOOP
FETCH ssn_cur
INTO id_sel_rel;
IF no_more_rel_rows THEN
CLOSE ssn_cur;
LEAVE the_rel_loop;
END IF;
INSERT INTO `ssn_related` ( `ssn_primary`, `ssn_related` ) VALUES ( id_sel_id, id_sel_rel ), ( id_sel_rel, id_sel_id );
END LOOP the_rel_loop;
END LOOP the_loop;
END$$
DELIMITER ;
How do i nest to use the values and insert into third table.
Cursors are slow and most of the time unnecessary. Nested cursors are slow² and unnecessary². Cursors shall only be used as the last resort, when there's really no other way.
What you want to do can be broken down to this:
INSERT INTO `ssn_related` ( `ssn_primary`, `ssn_related` )
SELECT
ssn_1.id,
ssn_2.id
FROM
ssn ssn_1
INNER JOIN ssn ssn_2 ON ssn_2.ssn = ssn_1.id
WHERE ssn_1.ssn NOT IN ('', '000-00-0000')
AND ssn_2.id != ssn_1.id;
Then you do the same again with swapped columns in the SELECT.
INSERT INTO `ssn_related` ( `ssn_primary`, `ssn_related` )
SELECT
ssn_2.id,
ssn_1.id
FROM
ssn ssn_1
INNER JOIN ssn ssn_2 ON ssn_2.ssn = ssn_1.id
WHERE ssn_1.ssn NOT IN ('', '000-00-0000')
AND ssn_2.id != ssn_1.id;
Related
I just started learning MySQL and am having trouble compiling a procedure.
It's giving me an error undefined cursor. I looked up a few examples on this forum and corrected my code but it still throws the same error.
DELIMITER $
CREATE PROCEDURE MY_PROC()
BLOCK1: BEGIN
DECLARE LOOP1_DONE BOOLEAN DEFAULT FALSE;
DECLARE VAR_TKR VARCHAR(100) DEFAULT 0;
DECLARE TKR_VALUE VARCHAR(100) DEFAULT 0;
-- OTHER VARIABLE DECLARATIONS
DECLARE CUR1 CURSOR FOR SELECT DISTINCT TKR FROM STG_TBL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET LOOP1_DONE = TRUE;
-- SET VARIABLE VALUES
OPEN CUR1;
CUR1_LOOP: LOOP
FETCH CUR1 INTO VAR_TKR;
IF LOOP1_DONE THEN
CLOSE CUR1;
LEAVE CUR1_LOOP;
END IF;
-- OTHER SELECT STATEMENTS AND CALCULATIONS
BLOCK2: BEGIN
DECLARE LOOP2_DONE BOOLEAN DEFAULT FALSE;
DECLARE CUR1_DATA CURSOR FOR
SELECT TKR_VALUE
FROM STG_VALUE_TBL
WHERE TKR = VAR_TKR
ORDER BY TKR_DATE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET LOOP2_DONE = TRUE;
OPEN CUR1_DATA;
-- SET VARIABLE VALUES
CUR1_DATA_LOOP: LOOP
FETCH CUR1_DATA INTO TKR_VALUE;
IF LOOP2_DONE THEN
CLOSE CUR1_DATA;
LEAVE CUR1_DATA_LOOP;
END IF;
-- OTHER SELECT STATEMENTS AND CALCULATIONS
END LOOP CUR1_DATA_LOOP;
END BLOCK2;
-- CLOSE CUR1_DATA; <removed as not needed>
END LOOP CUR1_LOOP;
-- CLOSE CUR1; <removed as not needed>
END BLOCK1;
$
DELIMITER;
Please find below table and sample data:
CREATE TABLE STG_TBL
(
ID NUMERIC(38),
TKR VARCHAR(10) NOT NULL
);
INSERT INTO STG_TBL VALUES (100000,'TKR1');
INSERT INTO STG_TBL VALUES (200000,'TKR2');
INSERT INTO STG_TBL VALUES (300000,'TKR3');
COMMIT;
CREATE TABLE STG_VALUE_TBL
(
TKR_DATE DATE,
TKR VARCHAR(10),
TKR_VALUE DECIMAL(20,10),
ADDED_DATE DATE
);
INSERT INTO STG_VALUE_TBL VALUES ('01-01-2015','TKR1','10.231','01-30-2016');
INSERT INTO STG_VALUE_TBL VALUES ('01-02-2015','TKR1','18.151','01-30-2016');
INSERT INTO STG_VALUE_TBL VALUES ('01-03-2015','TKR1','22.952','01-30-2016');
COMMIT;
Can anyone shed light on why this will not loop through the function and populate the temp table? Ive tried a number of things and at best can only get the first value to populate. I'm trying to take a value and a ":" separated string (queried in this procedure) to populate a table so I can reference it in a larger query. The function SPLIT_STR works great on its own but I cant seem to increment value "a" so that it separates ALL values per field per value.
BEGIN
DECLARE platform_val VARCHAR(255);
DECLARE productName_val VARCHAR(255);
DECLARE no_more_rows BOOLEAN;
DECLARE num_rows INT DEFAULT 0;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE str VARCHAR(255);
DECLARE a INT DEFAULT 1;
DECLARE cur1 CURSOR FOR SELECT
ProductName,
ProductPlatforms
FROM Feed
limit 10;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
OPEN cur1;
select FOUND_ROWS() into num_rows;
the_loop: LOOP
FETCH cur1
INTO productName_val,
platform_val;
SET str = platform_val;
WHILE a< num_rows DO
SET str=SPLIT_STR(str,":",a);
insert into temp values (productName_val, str);
SET a=a+1;
END WHILE;
END LOOP the_loop;
END
This is the idea I came up with
CREATE PROCEDURE `col2lines`()
BEGIN
declare v_platform,v_productName,v_platformAll varchar(255) default null;
declare v_finished int default 0;
declare curs cursor for select ProductName,ProductPlatforms from Feed limit 10;
declare continue handler for not found set v_finished = 1;
drop temporary table if exists temp_table;
create temporary table temp_table (
productName varchar(255),
platform varchar(255)
);
open curs;
parent: LOOP
fetch curs into v_productName, v_platformAll;
if (v_finished = 1) then LEAVE parent; end if;
child: LOOP
set v_platform = substring_index(v_platformAll, '::', 1);
set #strlen = char_length(v_platform);
if (#strlen > 0) then
insert into temp_table values (v_productName, v_platform);
set v_platformAll = substr(v_platformAll, #strlen + 3);
iterate child;
end if;
LEAVE child;
END LOOP child;
iterate parent;
END LOOP parent;
close curs;
select * from temp_table;
END
Mysql cursor issue?
I have written a stored procedure which will travel's record from one table and insert those into 2-3 different tables
using insert statements.
Problem is that i am checking if record is not exists in table1 then I am inserting record from temptable to table1 ,table2 sequentially
,but the condition is having some problem i don't know it its always going into else part.
Code sample is as follows:
CREATE PROCEDURE `insertData`(In clientNo INT,In usedID INT)
BEGIN
declare mame varchar(100);
declare address varchar(100);
declare city varchar(50);
declare IdentityNO1 varchar(20)
declare cur1 cursor for select * from temptable;
declare continue handler for not found set done=1;
SET #clientNo = clientNO;
SET #userID = userID;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into Name,Address,City,IdentityNO1,clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF ( (SELECT COUNT(*) FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo) < = 0)
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
end loop igmLoop;
close cur1;
END
There is no THEN nor END IF keywords, the procedure cannot compile.
Check this link for proper syntax of IF statement: http://dev.mysql.com/doc/refman/5.7/en/if.html
Use EXIST operator instead of (SELECT count(*)... ) <=0,
read this link to know the reason: http://sqlblog.com/blogs/andrew_kelly/archive/2007/12/15/exists-vs-count-the-battle-never-ends.aspx
IF EXISTS(
SELECT null FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo
)
THEN
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
END IF;
I recommend using some prefixes for procedure arguments and variable names to avoid ambiguity, for example use p_ for parameters and v_ for variables. It's hard to guess, looking at this code, which name is a column name, a variable or a procedure parameter. This can lead to mistakes and errors.
Avoid using SELECT * - this code will fail if someone will change the table structure. Explicitely list required columns in the cursor declaration:
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
The corrected procedure might look like this:
CREATE PROCEDURE `insertData`(In p_clientNo INT,In p_usedID INT)
BEGIN
declare v_name varchar(100);
declare v_address varchar(100);
declare v_city varchar(50);
declare v_IdentityNO varchar(20)
declare v_clientNo int
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
declare continue handler for not found set done=1;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into v_name,v_Address,v_City,v_IdentityNO,v_clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF EXISTS( SELECT 1 FROM table1
WHERE IndentityNo = v_IdentityNo
AND clientNo = v_clientNo)
INSERT INTO table1 (Name,IdentityNO) VALUES (v_name,v_IdentityNO);
INSERT INTO table2 (Address,City) VALUES(v_address,v_city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(v_name,v_address,v_city,v_IdentityNo);
END IF;
end loop igmLoop;
close cur1;
END
I have a table that stores some comma separated strings. Is there a way to write a sql to
return me a separate rows for each token string obtained by splitting across commas.
You can simply write and call a stored procedure
DELIMITER $$
DROP PROCEDURE IF EXISTS explode_table $$
CREATE PROCEDURE explode_table(bound VARCHAR(255))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value TEXT;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT table1.id, table1.value
FROM table1
WHERE table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2(
`id` INT NOT NULL,
`value` VARCHAR(255) NOT NULL
) ENGINE=Memory;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurance = (SELECT LENGTH(value)
- LENGTH(REPLACE(value, bound, ''))
+1);
SET i=1;
WHILE i <= occurance DO
SET splitted_value =
(SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(value, bound, i),
LENGTH(SUBSTRING_INDEX(value, bound, i - 1)) + 1), ',', ''));
INSERT INTO table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
SELECT * FROM table2;
CLOSE cur1;
END; $$
-------------------
CALL explode_table(',');
I have a table containing 100,000+ records from which i have some calculations to do based on a value which is stored in a specific column.
For this i have written a stored procedure which takes 100 rows at a time from the base table. Since cursors don't support dynamic sql. What i did was i create a dynamic view and the cursor always selects data from that view.
The code :
BEGIN
-- VARIABLES TO RETURN
DECLARE ORIG_COUNT INT ;
DECLARE SERVED_COUNT INT;
-- VARIABLED FOR LOOPING
DECLARE no_more_rows BOOLEAN;
DECLARE no_more_rows_sub BOOLEAN;
DECLARE num_rows INT DEFAULT 0;
SET #ORIG_COUNT =0;
SET #SERVED_COUNT=0;
SELECT COUNT(*) FROM table_one AS A WHERE A.year='2011' INTO #ORIG_COUNT ;
DELETE FROM table_test;
insert into table_test values ('Total Rows',#ORIG_COUNT,NULL);
DROP TABLE IF EXISTS table_request;
CREATE TABLE table_request (
BN_NUM VARCHAR(25) NOT NULL,
DN_NUM varchar(10) NOT NULL,
A_TOTAL FLOAT DEFAULT 0,
B_TOTAL FLOAT DEFAULT 0,
C_TOTAL FLOAT DEFAULT 0,
PRIMARY KEY (BN)
);
WHILE (#SERVED_COUNT<#ORIG_COUNT) DO
DROP VIEW IF EXISTS pbs_history.temp_view;
SET #query = CONCAT('CREATE VIEW temp_view as SELECT A.BN,A.DN
FROM table_one AS A
WHERE A.year='2011'
ORDER BY A.ID
LIMIT ', #SERVED_COUNT,',100');
PREPARE stmt from #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
/* ================= HERE ==================== */
SELECT * FROM temp_view;
BLOKA:BEGIN
DECLARE BN VARCHAR(25);
DECLARE DN VARCHAR(10);
DECLARE num_rows INT(5) DEFAULT 0;
DECLARE bn_count INT(5) DEFAULT 0;
DECLARE sel_recs CURSOR FOR SELECT * FROM temp_view;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
insert into table_test values('Start Served',#SERVED_COUNT,#query);
OPEN sel_recs;
SELECT FOUND_ROWS() INTO #num_rows;
insert into table_test values('Found Rows in View',#num_rows,NULL);
the_loop: LOOP
FETCH sel_recs INTO BN,DN;
IF no_more_rows THEN
CLOSE sel_recs;
LEAVE the_loop;
END IF;
SET #bn_count=0;
SELECT COUNT(*) FROM table_request WHERE BILL_NUMBER=BN INTO #bn_count;
insert into table_test VALUES(BN,DN,#bn_count);
IF(#bn_count=0) THEN
INSERT INTO table_request VALUES (BN,DN,0,0,0);
END IF;
BLOKB:BEGIN
DECLARE CAT VARCHAR(5);
DECLARE T1 FLOAT;
DECLARE data_fetch CURSOR FOR SELECT CAT_ID, TYPE_1 FROM transactions WHERE ID=BN;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows_sub = TRUE;
OPEN data_fetch;
sub_loop: LOOP
FETCH data_fetch INTO CAT,T1;
IF no_more_rows_sub THEN
CLOSE data_fetch;
LEAVE sub_loop;
END IF;
IF (CAT='P1') THEN
UPDATE table_request SET A_TOTAL = A_TOTAL+T1 WHERE BN_NUM=BN;
ELSEIF (CAT='P2') THEN
UPDATE table_request SET B_TOTAL = B_TOTAL+T1 WHERE BN_NUM=BN;
ELSEIF (CAT='P3') THEN
UPDATE table_request SET N_TOTAL = N_TOTAL+T1 WHERE BN_NUM=BN;
END IF;
END LOOP sub_loop;
END BLOKB;
SET #SERVED_COUNT = #SERVED_COUNT+1;
END LOOP the_loop;
insert into table_test values ('End the_loop',0,NULL);
END BLOKA;
END WHILE;
END
I'm testing the code with a subset from the original table. And the subset has 461 records.
And with this code there should be 5 iterations. And in the final iteration the view should contain only 61 records. But with this code each iteration has 100 records, and during each iteration it takes into consideration only the first 100 records.
But if i run SELECT * FROM temp_view in mysql console after the procedure has run, it shows the last 61 records.
Anybody can point out what i'm doing wrong here?