similar to StackOverflowPosting I would like to calculate the Levenshtein Distance for a m x n matrix consisting of TITLE1 and TITLE2.
My Levenshtein Functions works fine and is from here: LD
But my Question is how can I loop through the m x n in a UDF?
The Result should be a table with m x n rows with LD, TITLE1 and TITLE2.
I have done this - BUT I ALWAYS GET AN ERROR
1338 Cursor Declaration after Handler Declaration
My UDF looks like this:
BEGIN
DECLARE bDone INT;
DECLARE bDone1 INT;
DECLARE var2 varCHAR(255); -- or approriate type
DECLARE Var1 INT;
DECLARE c1Var1 VARCHAR(250);
DECLARE curs CURSOR FOR SELECT recid as BIOTIrecid, replace(replace(BIOGRAPHYTITLE," [in SCOPUS]",""),"[SIMILAR]","") as bioti FROM BIO ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
DECLARE curs1 CURSOR FOR SELECT trim(concat(scopus.Titel," ",scopus.Untertitel)) as scopusti FROM scopus ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
DROP TABLE IF EXISTS LDResults;
CREATE TABLE `LDResults` (
`BIOGRAPHYTITLE` varchar(255) DEFAULT NULL,
`recid` int(11) NOT NULL AUTO_INCREMENT,
`BIOTIrecid` int(11) default NULL,
`LD` varchar(255) DEFAULT NULL,
`ScopusTI` varchar(255) DEFAULT NULL,
PRIMARY KEY (`recid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
OPEN curs1;
SET bDone1 = 0;
#---------------- run all rows for scopusti
REPEAT
FETCH curs1 into c1var1;
#-----------------------------------------
OPEN curs;
SET bDone = 0;
#----- run all COLUMNs for biographytitle
REPEAT
FETCH curs INTO var1, var2;
INSERT INTO LDResults (`BIOGRAPHYTITLE`, `BIOTIrecid`, `LD`, `ScopusTI`) VALUES (var2, var1, LEVENSHTEIN(var2,c1var1), c1var1);
UNTIL bDone END REPEAT;
#--------------------------------------------
CLOSE curs;
UNTIL bDone1 END REPEAT;
CLOSE curs1;
SELECT * FROM LDResults;
END
Is my way to solve this problem sophisticated or could this be done on a more faster and better solution ?
Thanks for all advices.
EDIT:
I could make it with a counter here: Any comments?
BEGIN
-- DECLARE bDone INT;
-- DECLARE bDone1 INT;
DECLARE i INT;
DECLARE var2 varCHAR(255); -- or approriate type
DECLARE Var1 INT;
DECLARE cVar1 VARCHAR(250);
DECLARE curs1 CURSOR FOR SELECT trim(concat(t.Titel," ",t.Untertitel)) as scopusti FROM tscopus t ;
DECLARE curs CURSOR FOR SELECT recid as BIOTIrecid, replace(replace(BIOGRAPHYTITLE," [in SCOPUS]",""),"[SIMILAR]","") as bioti FROM tBIO ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
#DECLARE curs1 CURSOR FOR SELECT trim(concat(t.Titel," ",t.Untertitel)) as scopusti FROM tscopus t ;
#DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
DROP TABLE IF EXISTS LDResults;
CREATE TABLE `LDResults` (
`BIOGRAPHYTITLE` varchar(255) DEFAULT NULL,
`recid` int(11) NOT NULL AUTO_INCREMENT,
`BIOTIrecid` int(11) default NULL,
`LD` varchar(255) DEFAULT NULL,
`ScopusTI` varchar(255) DEFAULT NULL,
PRIMARY KEY (`recid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
OPEN curs1;
SET i = 0;
SET bDone1 = 0;
-- ---------------- run all rows for scopusti
REPEAT
FETCH curs1 into cvar1;
set i=(i+1);
-- -----------------------------------------
OPEN curs;
SET bDone = 0;
-- ----- run all COLUMNs for biographytitle
REPEAT
FETCH curs INTO var1, var2;
INSERT INTO LDResults (`BIOGRAPHYTITLE`, `BIOTIrecid`, `LD`, `ScopusTI`) VALUES (var2, var1, LEVENSHTEIN(var2,cvar1), cvar1);
UNTIL bDone END REPEAT;
-- --------------------------------------------
CLOSE curs;
UNTIL (i >= 2) END REPEAT;
CLOSE curs1;
SELECT * FROM LDResults;
END
I mean you can do it by next way useng CROSS JOIN without loops in your code. CROSS JOIN by definition return product of two tables rows result.
So you can use this result and after some data manipulation insert the result into new table like:
DROP TABLE IF EXISTS LDResults;
CREATE TABLE `LDResults` (
`BIOGRAPHYTITLE` varchar(255) DEFAULT NULL,
`recid` int(11) NOT NULL AUTO_INCREMENT,
`BIOTIrecid` int(11) default NULL,
`LD` varchar(255) DEFAULT NULL,
`ScopusTI` varchar(255) DEFAULT NULL,
PRIMARY KEY (`recid`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO LDResults (`BIOGRAPHYTITLE`, `BIOTIrecid`, `LD`, `ScopusTI`)
SELECT bioti, BIOTIrecid, LEVENSHTEIN(bioti,scopusti), scopusti
FROM (
SELECT
replace(replace(BIO.BIOGRAPHYTITLE," [in SCOPUS]",""),"[SIMILAR]","") as bioti,
BIO.recid as BIOTIrecid,
trim(concat(scopus.Titel," ",scopus.Untertitel)) as scopusti
FROM scopus
CROSS JOIN BIO
) tbl;
Related
I have following stored procedure that contains cursor.
But don't getting actual id field value and always show zero.
CREATE PROCEDURE `comm_pay_intro`(IN `id` VARCHAR(20), IN `comm_type` VARCHAR(50))
BEGIN
DECLARE i INTEGER;
DECLARE userid varchar(20);
DECLARE idx int(11);
DECLARE curs1 CURSOR FOR SELECT `id`, `user_id`
FROM `temp_table` order by `id`;
set i=1;
OPEN curs1;
read_loop: LOOP
FETCH curs1 INTO idx,userid;
insert into user_commission(rate_id, user_id)
VALUES(1, idx);
END LOOP read_loop;
CLOSE curs1;
END
I'm working on an Android program that introduces in a table approximately 15000 integer values(somewhere between 350-500 lines with 32 columns). In the DB I also have other similar values. This 15000 values that I'm talking about represent a processed image, so basically I want to compare the similarity of two images. Now, when I try to compare the values of two images(I'm comparing value by value and count the equal ones), only the data writing process takes about 7 minutes, which is way too long(I want to be able to write and compare at least 5 images in that time). I know that usually you don't work with this kind of things directly in the DB, but do you think that there is anything that I can do, or is it necessary to do this comparison on the server? The values returned by the descriptor came as line elements separated by ',' and each line is separated by ';'. I take each returned element and save it in a tables column. Here is my code:
Split function:
CREATE DEFINER=`root`#`localhost` FUNCTION `strSplit`(textIn longtext, delim varchar(12), count int) RETURNS int(11)
BEGIN
declare splitString INT(11);
SET splitString = replace(substring(substring_index(textIn, delim, count), length(substring_index(textIn, delim, count - 1)) + 1), delim, '');
RETURN splitString;
END
The function that creates the table:
CREATE TABLE IF NOT EXISTS `myguide`.`objectlocation` (
`ObjectLocationId` INT(11) NOT NULL AUTO_INCREMENT,
`ValueObject` LONGTEXT NOT NULL,
`DescriptorSize` INT(11) NOT NULL,
`DescriptionObject` VARCHAR(45) NOT NULL,
`DataInsert` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`InsertBy` VARCHAR(45) NULL DEFAULT NULL,
PRIMARY KEY (`ObjectLocationId`))
ENGINE = InnoDB
AUTO_INCREMENT = 2
DEFAULT CHARACTER SET = utf8
And this is the code that does the insert part:
CREATE DEFINER=`root`#`localhost` PROCEDURE `myguide_sp_info_imageId`(descriptorIn longtext, sizeDescriptor INT)
BEGIN
declare sizeImagesTable INT DEFAULT (select count(*) from objectLocation);
declare descriptorSizeImage INT;
declare descriptor INT;
declare sizeDescriptorImage INT DEFAULT sizeDescriptor;
declare contorInsertImage INT default 1;
declare descriptorForSplit longtext;
declare descriptorImageSaved longtext;
declare descriptorForSplitImageSaved longtext;
/* check if table exist, drop*/
DROP TEMPORARY TABLE IF EXISTS backupObjectLocation;
/* Create temporar table for store info about objectLocation*/
CREATE TEMPORARY TABLE backupObjectLocation (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
idImage int NOT NULL,
descriptorSaved longtext not null,
sizeDescriptorSaved float not null
);
/* check if table exist, drop*/
DROP TEMPORARY TABLE IF EXISTS processImage;
/* Create temporar table for store info about objectLocation*/
CREATE TEMPORARY TABLE processImage (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
descriptorSaved varchar(255) ,
descriptorReceived varchar(255)
);
SET descriptorImageSaved = RTRIM(descriptorIn);
SET descriptorForSplit = REPLACE(descriptorImageSaved, ';', ',');
INSERT INTO backupObjectLocation (idImage, descriptorSaved, sizeDescriptorSaved)
SELECT ObjectLocationId, ValueObject, DescriptorSize FROM objectLocation;
loop_insertDescriptorImage: LOOP
if contorInsertImage > sizeDescriptorImage then
leave loop_insertDescriptorImage;
end if;
SET descriptor = strSplit(descriptorForSplit, ',', contorInsertImage);
INSERT INTO processImage (descriptorReceived) VALUES (descriptor);
SET contorInsertImage = contorInsertImage + 1;
ITERATE loop_insertDescriptorImage;
end LOOP;
loop_table: LOOP
if sizeImagesTable > 1 then
leave loop_table;
end if;
SET descriptorSizeImage = (SELECT sizeDescriptorSaved from backupObjectLocation where id = sizeImagesTable);
loop_image: LOOP
if descriptorSizeImage > 1 then
leave loop_image;
end if;
SET descriptorImageSaved = (SELECT descriptorSaved from backupObjectLocation where id = sizeImagesTable);
SET descriptorForSplitImageSaved = REPLACE(descriptorImageSaved, ';', ',');
SET descriptorSizeImage = descriptorSizeImage + 1;
ITERATE loop_image;
end LOOP;
SET sizeImagesTable = sizeImagesTable + 1;
ITERATE loop_table;
end LOOP;
select descriptorImageSaved;
select * from backupObjectLocation;
select * from processImage;
END
Please help me find a solution.
I created two columns in student table for my database. I now need to create a cursor for the student table. I need to make use of the input parameters for start and end student Id’s to filter the results in the cursor query.
I also need to open the cursor created and check if the student has an email assigned or not. If the email is not assigned I need to update the email column to have an email assigned to the student.
Finally to why I want help:
I cannot figure out how I would write the case statements for this cursor. I have tried to think of a good way to do this and not succeeded. Please help!!
DELIMITER $
DROP PROCEDURE IF EXISTS CURSOR_DEMO$
CREATE PROCEDURE CURSOR_DEMO(start_student_id INT
,end_student_id INT
)
BEGIN
DECLARE l_table_name VARCHAR(50);
DECLARE iam_done INT DEFAULT 0;
DECLARE l_sql_stmt VARCHAR(5000);
SET #l_sql_stmt='ALTER TABLE STUDENT ADD EMAIL VARCHAR';
SELECT #l_sql_stmt;
prepare stmt from #l_sql_stmt;
execute stmt;
SET #l_sql_stmt='ALTER TABLE STUDENT ADD PHONE int(10)';
SELECT #l_sql_stmt;
prepare stmt from #l_sql_stmt;
execute stmt;
DECLARE TBL_CUR CURSOR FOR
SELECT EMAIL FROM STUDENT.TABLES WHERE TABLE_SCHEMA='MYSQLDB';
BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET IAM_DONE=1;
OPEN TBL_CUR;
tbl_loop:LOOP
FETCH tbl_cur INTO l_table_name;
IF IAM_DONE = 1 THEN
LEAVE tbl_loop;
END IF;
CASE WHEN l_table_name = 'STUDENT' THEN
ELSE BEGIN END;
END CASE;
END LOOP tbl_loop;
CLOSE TBL_CUR;
END;
END$
DELIMITER ;
Is this the kind of thing you need?
/*
drop table student;
delimiter $$
CREATE TABLE `student` (
`id` int(11) NOT NULL ,
`name` char(1) NOT NULL,
`email` varchar(1),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8$$
drop table email;
delimiter $$
CREATE TABLE `email` (
`id` int(11) NOT NULL ,
`type` varchar(8) NOT NULL,
`person_id` int,
`email` varchar(1),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8$$
;
*/
DELIMITER $
DROP PROCEDURE IF EXISTS CURSOR_DEMO$
CREATE PROCEDURE CURSOR_DEMO(start_student_id INT
,end_student_id INT)
BEGIN
declare email_person_id int;
declare email_address varchar(50);
DECLARE done INT DEFAULT 0;
DECLARE CUR CURSOR FOR
SELECT person_id,email FROM sandbox.email where type = 'student';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN CUR;
cur_loop:LOOP
IF done = 1 THEN
LEAVE cur_loop;
END IF;
FETCH CUR INTO email_person_id,email_address;
update student
set email = email_address
where id = email_person_id
and email is null
;
END LOOP cur_loop;
CLOSE CUR;
commit;
END$
DELIMITER ;
truncate table student;
insert into student
values
(1,'A','1'),
(2,'B','1'),
(3,'C',null),
(4,'D',null),
(5,'E',null),
(6,'G',null),
(7,'F',null)
;
truncate table email;
insert into email
values
(1,'student',1,'a'),
(2,'student',2,'b'),
(3,'faculty',7,'z'),
(4,'student',3,'c')
;
select * from student;
call cursor_demo(1,10);
select * from student;
I'm experiencing a 'Column cannot be null' error for 2 columns, when I try to run a SP.
Source table A is defined as below:
CREATE TABLE `test_data`.`offer` (
`id` INT NOT NULL,
`hotel_id` INT NOT NULL,
`currency_id` INT NOT NULL,
`source_system_code` VARCHAR(64) NOT NULL,
`available_cnt` INT NOT NULL,
`sellings_price` FLOAT NOT NULL,
`checkin_date` DATE NOT NULL,
`checkout_date` DATE NOT NULL,
`valid_offer_flag` TINYINT(1) NOT NULL,
`offer_valid_from` DATETIME NOT NULL,
`offer_valid_to` DATETIME NOT NULL,
`breakfast_included_flag` TINYINT(1) NOT NULL,
`insert_datetime` DATETIME NOT NULL,
PRIMARY KEY (`id`));
Table B into which I am inserting the data:
CREATE TABLE `calculate_USD` (
`counter` int(11) NOT NULL AUTO_INCREMENT,
`dates` date DEFAULT NULL,
`id` int(11) NOT NULL,
`hotel_id` int(11) NOT NULL,
`original_price` int(11) NOT NULL,
`currency_id` int(11) NOT NULL,
PRIMARY KEY (`counter`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Here is the SP for the insertion:
CREATE PROCEDURE `test_procedure`()
BEGIN
DECLARE aid INT;
DECLARE avalid_from_date DATE;
DECLARE avalid_to_date DATE;
DECLARE hotel_id INT;
DECLARE original_price float;
DECLARE currency_id int;
DECLARE tempdt DATE;
DECLARE done INT DEFAULT FALSE;
DECLARE getdates CURSOR FOR
SELECT id,offer_valid_from,offer_valid_to,hotel_id,sellings_price,currency_id
from offer;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN getdates;
read_loop: LOOP
FETCH getdates
INTO aid,avalid_from_date,avalid_to_date,hotel_id,original_price,currency_id;
IF done THEN
LEAVE read_loop;
END IF;
set tempdt=date(avalid_from_date);
WHILE (tempdt <= date(avalid_to_date)) do
insert into calculate_USD(dates,id,hotel_id,original_price,currency_id)
values(tempdt,aid,hotel_id,original_price,currency_id);
set tempdt=tempdt+INTERVAL 1 DAY;
end while;
END LOOP;
CLOSE getdates;
END
//
When I call the SP,
hotel_id & currency_id columns are instigating the error code.
If I assign them both NULL default values, the SP runs however, the hotel_id & currency_id values being inserted are all NULL like so (rest are OK):
counter | dates | id | hotel_id | original_price | currency_id |
1 | 2015-4-30 | 342523| NULL | 200 | NULL |
2 | 2015-4-30 | 342524| NULL | 112 | NULL |
This is strange, because both have valid data in the source table.
Please advise.
One option that can solve is:
.
.
.
DECLARE `getdates` CURSOR FOR
SELECT
`id`,
`offer_valid_from`,
`offer_valid_to`,
-- `hotel_id`,
`offer`.`hotel_id`,
`sellings_price`,
-- `currency_id`
`offer`.`currency_id`
FROM
`offer`;
.
.
.
So I figured it out.
All I had to do was re-name the hotel_id & currency_id variables in the SP to something else and it worked.
Updated SP:
delimiter //
CREATE PROCEDURE `test_procedure`()
BEGIN
DECLARE aid INT;
DECLARE avalid_from_date DATE;
DECLARE avalid_to_date DATE;
DECLARE sp_hotel_id INT;
DECLARE original_price float;
DECLARE sp_currency_id int;
DECLARE tempdt DATE;
DECLARE done INT DEFAULT FALSE;
DECLARE getdates CURSOR FOR
SELECT id,offer_valid_from,offer_valid_to,hotel_id,sellings_price,currency_id
from offer;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN getdates;
read_loop: LOOP
FETCH getdates
INTO aid,avalid_from_date,avalid_to_date,sp_hotel_id,original_price,sp_currency_id;
IF done THEN
LEAVE read_loop;
END IF;
set tempdt=date(avalid_from_date);
WHILE (tempdt <= date(avalid_to_date)) do
insert into calculate_USD(dates,id,hotel_id,original_price,currency_id)
values(tempdt,aid,sp_hotel_id,original_price,sp_currency_id);
set tempdt=tempdt+INTERVAL 1 DAY;
end while;
END LOOP;
CLOSE getdates;
END
//
call test_procedure();
I am constantly getting a Error code 1062: Duplicate Entry.
The first row insert, but then it fails on the same ID.
So everytime I hit execute it will increment: 1466, 1467, 1468, 1469.
And each time there is the same record entered, so I am assuming the autoincrement is only working for the first iteration.
Table:
'entity':
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL,
`enterprise_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1474 DEFAULT CHARSET=latin1 COMMENT=\'Comment'
Stored procedure:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `tp_to_entityPROC`()
DETERMINISTIC
COMMENT 'stored'
BEGIN
DECLARE done BOOLEAN DEFAULT 0;
DECLARE Tid INT;
DECLARE Tt_name TEXT;
DECLARE allt CURSOR FOR
SELECT training_provider_id, training_provider_name
FROM training_providers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN allt;
read_loop: LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH allt INTO Tid, Tt_name;
SET #id = 0;
SET #t_name = 0;
SET #id = Tid;
SET #t_name = Tt_name;
SET #empty = '';
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);
SET #my_id = LAST_INSERT_ID();
IF #my_id != 0 THEN
UPDATE training_awarded_providers
SET training_awarded_provider_id = #my_id
WHERE training_awarded_provider_id = #id;
END IF;
END IF;
END LOOP;
CLOSE allt;
END
Not sure about the exact error of duplicate entry but your posted code is not going to work.
Your Table schema
CREATE TABLE `entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`reg_num` varchar(45) NOT NULL <-- Here it's non null column
In your store procedure you are trying to insert null to reg_num column which will never succeed
if (#id != 0) THEN
INSERT INTO entity (name)
VALUES (#t_name);