MySQL 1329 Error No Data - Zero rows fetched - mysql

I have searched SO, for similar and I found one other posting similar to this and I followed what I thought was the follow up but I'm still seeing a problem.
I have also been sifting through the MySQL manuals, and what I have here looks like it is correct.
DELIMITER $$
CREATE DEFINER=`perimUser`#`localhost` PROCEDURE `assignLOBId`()
BEGIN
declare id, done INT default 0;
declare name VarChar(45);
declare lobCursor Cursor for Select idLineOfBusiness as id, name from LineOfBusiness;
declare continue handler for not found set done = 1;
OPEN lobCursor;
my_loop: LOOP
FETCH lobCursor INTO id, name;
IF done = 1 THEN
CLOSE lobCursor;
LEAVE my_loop;
END IF;
insert into test values (id, name);
UPDATE medium set idLOB = id where LOB = name;
UPDATE low set idLOB = id where LOB = name;
End LOOP my_loop;
END
I have run the Query that I"m using for the cursor and it does return 13 rows. Tables medium and low are full of data about 600 rows in each. the LOB match values in the LOB column of each. The values that were used to create the ones in lineofbusiness were generated from medium and low.
The goal here is to use this pattern a number of times as I work to normalized the data in medium and low. Otherwise I'd take the short cut and create a bunch of manual update statements.

I'm not too sure why your cursor isn't working as expected (you don't say whether your test table is populated with the results that you expect?), but it appears to me your procedure is simply implementing a multiple-table UPDATE (so can probably be entirely replaced with the following):
UPDATE LineOfBusiness
LEFT JOIN medium ON LineOfBusiness.name = medium.LOB
LEFT JOIN low ON LineOfBusiness.name = low.LOB
SET medium.idLOB = LineOfBusiness.idLineOfBusiness
, low.idLOB = LineOfBusiness.idLineOfBusiness

Related

Want to generate unique Id's using a function in mysql

I wrote a function to generate unique id's,its working but sometimes two people are getting same id,I mean duplicates are formed. My unique id looks like
2016-17NLR250001, I deal with only last four digits 0001. I am posting my function please correct it and please help me in avoiding duplicates even though users login into same account or if they do it on same time.
MY FUNCTION:
DELIMITER $$
USE `olmsap`$$
DROP FUNCTION IF EXISTS `fun_generate_uniqueid`$$
CREATE DEFINER=`root`#`%` FUNCTION `fun_generate_uniqueid`( V_DATE DATE,V_MANDALID INT ) RETURNS VARCHAR(30) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE MDLCODE VARCHAR(5);
SET MDLCODE = ' ';
SELECT COUNT(*) INTO #CNT FROM `st_com_mandal` WHERE MANDAL_VS_MC=V_MANDALID;
SELECT dist_mandal_code INTO MDLCODE FROM `st_com_mandal` WHERE MANDAL_VS_MC=V_MANDALID;
IF #CNT>0 THEN
SET #YR=`FUN_FISCAL_YR`(V_DATE);
SELECT CONCAT(IF(DIST_SAN_CODE='GUN','GNT',DIST_SAN_CODE),IFNULL(`dist_mandal_code`,'NULL'))INTO #MANDAL
FROM `st_com_dist` SCD INNER JOIN `st_com_mandal` STM ON STM.`mandal_dist_id`= SCD.`DIST_VC_DC` WHERE MANDAL_VS_MC=V_MANDALID;
IF MDLCODE >0 THEN
SELECT COUNT(Soil_Sample_ID)+1 INTO #ID FROM `tt_mao_soil_sample_dtls` WHERE MANDAL_ID=V_MANDALID AND SUBSTR(UNIQUE_ID,1,7)=#YR ;
ELSE
SELECT COUNT(Soil_Sample_ID)+1 INTO #ID FROM `tt_mao_soil_sample_dtls` WHERE SUBSTR(UNIQUE_ID,1,14)=CONCAT(#YR,#MANDAL) ;
END IF ;
IF LENGTH(#ID)=1 THEN
SET #ID=CONCAT('000',#ID);
ELSEIF LENGTH(#ID)=2 THEN
SET #ID=CONCAT('00',#ID);
ELSEIF LENGTH(#ID)=3 THEN
SET #ID=CONCAT('0',#ID);
ELSE
SET #ID=#ID;
END IF ;
RETURN CONCAT(#YR,#MANDAL,#ID);
ELSE
RETURN 'Mandal Doesnt Exists';
END IF;
END$$
DELIMITER ;
I do not think community will be able to help you with this question. This is a complex function that requires very careful analysis of table / index access and locking.
The only thing I can recommend is to not use existing table data to calculate next sequence as this is a bad practice.
Besides Race conditions that you are experiencing you will also get problems if the record with the last sequence is deleted.
I suggest you read this to get an idea on how to write a custom sequence generator:
http://en.latindevelopers.com/ivancp/2012/custom-auto-increment-values/

Updating a column name of a same table which has a parent child relationship using mysql

I searched a lot of doing a task but found no appropriate solution.
Basically the scenario is. I have a user_comment table in which there are 5 column(id,parent_id,user_comments,is_deleted,modified_datetime). There is a parent child relationship like 1->2,1->3,2->4,2->5,5->7 etc. Now i am sending the id from the front end and i want to update the column is_deleted to 1 and modified_datetime on all the records on
this id as well as the all the children and children's of children.
I am trying to doing this by using a recursive procedure. Below is the code of my procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_comments`(
IN mode varchar(45),
IN comment_id int,
)
BEGIN
DECLARE p_id INT DEFAULT NULL ;
if(mode = 'delete')
then
update user_comment set is_deleted = 1, modified_datetime = now()
where id = comment_id ;
select id from user_comment where parent_id = comment_id into p_id ;
if p_id is not null
then
SET ##GLOBAL.max_sp_recursion_depth = 255;
SET ##session.max_sp_recursion_depth = 255;
call user_comments('delete', p_id);
end if;
end if;
END
By using this procedure it give me an error of more than one row.
If i return the select query without giving it to variable then shows me the the appropriate results on the select query but i have to call this procedure recursively based on getting the ids of the select query.
I need help i have already passed 2 days into this.
I used cursor also. Below is the code of cursor
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_comments`(
IN mode varchar(45),
IN comment_id int,
)
BEGIN
DECLARE p_emp int;
DECLARE noMoreRow INT;
DECLARE cur_emp CURSOR FOR select id from user_comment where parent_id = comment_id ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET noMoreRow = 0;
if(mode = 'delete')
then
OPEN cur_emp;
LOOPROWS: LOOP
IF noMoreRow = 0 THEN
update user_comment set is_deleted = 1, modified_datetime = now() where id = comment_id
CLOSE cur_emp;
LEAVE LOOPROWS;
END IF;
FETCH cur_emp INTO p_emp;
update user_comment set is_deleted = 1, modified_datetime = now() where id = p_emp ;
SET ##GLOBAL.max_sp_recursion_depth = 255;
SET ##session.max_sp_recursion_depth = 255;
call user_comments('delete', p_emp);
END LOOP;
end if;
END
After using cursor i am getting a thread error.i don't know how can overcome this problem!!!
Mysql's documentation on select ... into varlist clearly says:
The selected values are assigned to the variables. The number of
variables must match the number of columns. The query should return a
single row. If the query returns no rows, a warning with error code
1329 occurs (No data), and the variable values remain unchanged. If
the query returns multiple rows, error 1172 occurs (Result consisted
of more than one row). If it is possible that the statement may
retrieve multiple rows, you can use LIMIT 1 to limit the result set to
a single row.
Since you wrote in the OP that a comment can be parent of many comments, using simple variables cannot be a solution. You should use a CURSOR instead, that can store an entire resultset.
You loop through the records within the cursos as shown in the sample code in the above link and call user_comments() in a recursive way.
UPDATE
If your receive
Error Code: 1436. Thread stack overrun
error, then you can do 2 things:
Increase the thread_stack setting in the config file and restart mysql server.
You can try to simplify your code to use less recursions and therefore less stack space. For example, when you fetch all children into the cursor, then rather calling the user_comments() recursively for each, you can set all direct children's status within the code and call the function recirsively on grand-childrens only (if any). You can also change your data structure and use nested set model to approach hierarchical structures.
Nested set model is more complex to understand, it is less resource intensive to traverse, but more resource intensive to maintain.

MySQL Stored Procedure Search another table

I am totally new to Stored Procedures, but know that this could be more efficient than trying to write PHP+MySQL code each time I need to do something like this.
I have two tables. CapitalAssets, Systems
I want find all CapitalAssets.ServerName that are not null
I have to link the two tables together, the Systems table has IP addresses, hostname.
I want to (row-by-row) grab CapitalAssets.ServerName and search Systems.hostname, IF it is found I want to link/print
CapitalAssests: Systems.id, Systems.hostname, Systems.IP, CapitalAssets.id, CapitalAssets.ServerName
Here is my start to my stored procedure, It is wrong. I do not now how to pass the Systems.hostname to do the search (where the ? is)
begin
declare GSATcur cursor for
'select id,NEName,ManagementAddress FROM GSAT WHERE NEName like ?';
declare CapitalCurr CURSOR FOR
'SELECT id,SystemName FROM CapitalAssets WHERE SystemName != ""';
DECLARE start INT DEFAULT 0;
DECLARE sysname_not_found BOOL DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET sysname_not_found = TRUE;
OPEN GSATcur;
OPEN CapitalCur;
loop1:
WHILE start < 5 do
FETCH SystemName INTO NEName;
IF sysname_not_found THEN
LEAVE loop1;
END IF;
END WHILE;
CLOSE CapitalCur;
CLOSE GSATcur;
END;
The two tables are in the same dB.
" grab CapitalAssets.ServerName and search Systems.hostname, IF it is found I want to link/print "
If this is the ultimate goal. Try this
SELECT * FROM Systems
WHERE hostname IN ( SELECT DISTINCT(ServerName)
FROM CapitalAssets WHERE ServerName IS NOT NULL );
UPDATE CapitalAssets
INNER JOIN Systems
ON Systems.hostname = CapitalAssests.ServerName
SET CapitalAssets.ipAddress = Systems.ipAddress;
UPDATE CapitalAssets
SET ipAddress = ( SELECT ipAddress
FROM Systems
WHERE Systems.hostname = CapitalAssests.ServerName );

Mysql: replace string in one table based on information on another table

I have the following problem, this is going to be long, I want to tell exactly all what I know about my problem in my question.
I have a table, field_body_value, with two fields, body_value and body_summary, containing strings of the form "/webfm_send/#" where # is a number.
I have another table called webfm_file where I have two fields with information for the string substitution: the first one is called fid, and it is the number # that I mentioned before, and the second is called fpatch, and gives me a string holding a path (for instance /data/html/files/file1.pdf) which has to substitute /webfm_send/# in the first table. The numbers # go up over the records of webfm_file but there are jumps, that is they increase but there are missing # so the final # is not equal to the number of records in webfm_file
So I thought the strategy was to set up a procedure which loops over the second table, and at each step of the sequence retrieves the pair fid/fpath, searches for "/webfm_send/fid" in the first table, and substitutes this by fpath in the first table.
So this is as far a I could arrive with my coding:
BEGIN
DECLARE v1 INT DEFAULT 0;
SELECT COUNT(*) INTO #numrec FROM `webfm_file`;
WHILE v1 < #numrec DO
SELECT fpath,fid INTO #path,#file FROM `webfm_file` LIMIT v1,1;
SET #webfm = concat('/webfm_send/',#file);
SET #cpath = concat('/',#path);
UPDATE `field_data_body`
SET body_value = replace(body_value, #webfm, #cpath),
body_summary = replace(body_summary, #webfm, #cpath)
WHERE body_value LIKE concat('%',#webfm,'%') OR
body_summary LIKE concat('%',#webfm,'%');
SET v1 = v1 + 1;
END WHILE;
END
Let me explain what I think I'm doing with the code above:
1) I retrieve the number of records in webfm_file for the loop.
2) The first SELECT gets a pair in fpath/fid from webfm_file, with LIMIT v1,1 I just check one record at a time, I checked an it works, the while loops over each record of webfm_file and the records are retrieved correctly.
3) The two next "set" fix the pair of strings #file/#path to create #webfm whith is the way its written in body_value at field_body_value, and to put a slash in front of #cpath which is the way I need this string to finally appear.
4) Then comes the UPDATE which will actually substitute the string if it finds it in either body_value or body_summary of field_body_data.
Expected: each instance of /webfm_send/# is substituted by the corresponding fpath pair of # (fid) in webfm_file
What I actually get: All appearances of /webfm_send/# no matter the value of # are substituted by the value of fpath in record 1 of webfm_file.
Things I have tried:
1) Take out the "WHERE" clause in the UPDATE sentence, which I believe is not strictly necessary since the replace function already takes care of finding a match but could speed up things. Same result
2) Resctrict the loop to loop just over a single record of webfm_file. Here it works in substituting the corresponding single retrieved pair fid/fpath, in the two instances of body_value and body_summary in field_body_data where fid=# appears in the string webfm_send/#
Thanks for following my explanation until here and thanks in advance for any hint.
You could use a cursor to iterate over the replacement strings. (There are faster ways using group_concat and it would be easier to do this in a general-purpose language rather than in a stored procedure). The general cursor approach would be:
drop procedure if exists proc;
delimiter //
create procedure proc()
begin
declare done boolean default 0;
declare path varchar(255);
declare id int;
declare cur cursor for select fpath, fid from webfm_file order by fid desc;
declare continue handler for sqlstate '02000' set done = 1;
open cur;
block: loop
fetch cur into path, id;
if done then
leave block;
end if;
set #from = concat('/webfm_send/', id);
update field_data_body set
body_value = replace(body_value, #from, path),
body_summary = replace(body_summary, #from, path);
end loop;
close cur;
end//
delimiter ;
call proc();

Problems with syntax on MySQL trigger in PHP My Admin

I am having problems getting this trigger to work. Here is the code:
BEGIN
DECLARE newprice double;
DECLARE id int;
DECLARE rentdate DATE;
SET id := RESERVATION.RES_ID;
SET rentdate := "SELECT RES_RENT_DATE
FROM RESERVATION
WHERE RES_ID = id";
SET newprice := (NEW.RES_RETURN_DATE - rentdate)*RESERVATION.RES_CAR_PPD;
UPDATE RESERVATION
SET RESERVATION.RES_TOTAL_PRICE = newprice WHERE
RESERVATION.RES_ID = id;
END
Basically what I want to do is just update the total price when the return date of a car is changed. The trigger should execute on update of the Return Date. When updating it gives me the error: #1109 - Unknown table 'RESERVATION' in field list . I do not know what I am doing wrong.
There are several issues:
You can't arbitrarily refer to table columns like you did in SET id := RESERVATION.RES_ID;. You can refer to columns only either in a valid SQL statement (e.g. SELECT) or through NEW/OLD.
You can't issue DML statement (in your case UPADTE) on the same table on which you defined the trigger. This mutating behavior is prohibited in MySQL.
If I understand correctly and all values you need are in the same row, all you need is to use a BEFORE trigger. See example below.
Your trigger can be boiled down to this
CREATE TRIGGER tg_bu_reservation
BEFORE UPDATE ON reservation
FOR EACH ROW
SET NEW.res_total_price = (NEW.res_return_date - NEW.res_rent_date) * NEW.res_car_ppd;
Note: since it's a one statement trigger now there is no need in BEGIN...END block and changing a DELIMITER.
Here is SQLFiddle demo