查询运行无休止(嵌套游标/循环)-MySQL

时间:2018-12-21 23:49:20

标签: mysql stored-procedures database-cursor

我已经编写了此查询,但是可能找不到一些逻辑错误。游标或游标中的循环永远运行,一段时间后,我得到最大结果数达到错误。

谢谢。

    CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_update_productsearch_datasync`()
BEGIN

  DECLARE p_searchtext longtext default ''; 
  DECLARE p_broken_str VARCHAR(1000) default ''; 
  DECLARE p_alternative_str VARCHAR(1000) default ''; 
  DECLARE p_item int(11) default 0; 
  DECLARE search_loop_finished, alternative_search_loop_finished boolean default false; 

  DECLARE srchbox_cur CURSOR FOR SELECT DISTINCT item, searchbox 
  FROM  productsearch where searchbox is not null limit 10; 

  DECLARE continue HANDLER for NOT found SET search_loop_finished = true; 

  OPEN srchbox_cur;   
  srchbox_loop : loop   
  FETCH srchbox_cur INTO  p_item,p_searchtext; 

    set p_searchtext = replace(p_searchtext,' ','|'); 

    IF search_loop_finished then 
        close srchbox_cur;
        leave srchbox_loop; 
    END IF; 


    drop TABLE IF EXISTS split_vals;      
    create temporary TABLE split_vals(vals varchar(1000));  

      begin_block1: begin 
        DECLARE loop_idx  int DEFAULT 0; 
        declare idx       int DEFAULT 0; 
        declare start_idx int DEFAULT 1; 
        declare str       varchar(500); 
        declare cc        varchar(1); 

        split_val_loop : loop 
                SET loop_idx = loop_idx+1; 
                set idx=idx+1; 
                set str = substr(p_searchtext,start_idx,idx); 
                set cc = substr(p_searchtext,(start_idx+idx),1); 

                if cc = '|' THEN 
                    SET idx=idx+1; 
                    set start_idx = idx + start_idx; 
                    set idx=0; 
                    insert INTO split_vals VALUES (str ); 

                    set str = ''; 
                    set cc = ''; 
                elseif loop_idx = length(p_searchtext) THEN 
                    insert INTO split_vals VALUES (str); 

                leave split_val_loop; 
                end IF; 
            end LOOP split_val_loop;
        END begin_block1;

-- select * from split_vals;


    begin_block2 : Begin

      DECLARE alternative_search_cur CURSOR FOR SELECT DISTINCT vals FROM  split_vals; 

      DECLARE continue HANDLER for NOT found SET  alternative_search_loop_finished = true; 

      OPEN alternative_search_cur; 

      alternative_search_loop : loop 

        FETCH alternative_search_cur INTO  p_alternative_str; 

        IF alternative_search_loop_finished then 
            set alternative_search_loop_finished = false;
            close alternative_search_cur;
            leave alternative_search_loop; 
        END IF; 

        -- select search_b from Product_Search_Alternatives where search_a = p_alternative_str;
        select p_item,p_searchtext; 
        /*
        update productsearch
        set searchbox = Concat(searchbox,' ',v_alt_txt)
        where item = v_item;        
        */
        -- select v_alt_txt;

        END loop alternative_search_loop;

    end begin_block2;

END loop srchbox_loop;
END

1 个答案:

答案 0 :(得分:0)

尽管当您寻找替代匹配字符串时,您的过程在第二个块中有一些禁用的内容,但是我不确定您要获取的内容,所以我将该块大部分注释掉了。

您实际上还没有使用该项目,因此我将其删除。如果需要它,我将重新添加变量cursor和fetch,但是还需要添加要插入到SPLIT_VALS表中的列。

我的方法是使用INSTR()函数,该函数确定给定字符串或字符的第一个位置...在这种情况下,您正在寻找PIPE字符。确定之后,我将继续从字符串中删除字符串的任何部分,而只是对其进行处理,并因此继续缩小p_searchtext字符串,直到没有剩下任何东西为止。我认为您检查每个字符的逻辑一直失败,或者没有将此类项目视为双倍空格,因此创建了双倍“ ||”字符,并在循环中进行了介绍。

除了INSTR()以外,您还可以使用SUBSTRING_INDEX(str,delim,count)进行类似操作,以获取字符串,空值或找到的IF位置...希望这对您有所帮助...

CREATE DEFINER=`root`@`localhost` 
PROCEDURE `sp_update_productsearch_datasync`()
BEGIN
   -- regardless of any possible results,
   -- prepare temp table to store string split into word parts
   drop TABLE IF EXISTS split_vals;      
   create temporary TABLE split_vals(vals varchar(1000));  

   DECLARE p_searchtext longtext default ''; 
   DECLARE search_loop_finished boolean default false; 

   DECLARE srchbox_cur CURSOR FOR 
      SELECT DISTINCT searchbox 
         FROM  productsearch 
         where searchbox is not null 
         limit 10; 

   DECLARE continue HANDLER for NOT found 
      SET search_loop_finished = true; 

   open srchbox_cur;   
   srchbox_loop : loop   
      FETCH srchbox_cur INTO  p_searchtext; 
      -- exit immediately if no result
      IF search_loop_finished then 
         leave srchbox_loop; 
      END IF; 

      -- preset any SPACES into a common PIPE character
      set p_searchtext = rtrim(replace(p_searchtext,' ','|')); 

      declare str       varchar(500); 
      declare pipePos   int default 0;

      split_val_loop : loop 

         -- if no text string left to work with, exit loop
         if length(p_searchtext) = 0 THEN 
            leave split_val_loop; 
         end if; 


         -- does the p_searchtext have any more pipe characters left in it?
         set pipePos = INSTR('|', p_searchtext);

         -- in case there is a double space could create "test||strings|||more"
         -- you would never want to insert a "|" string value
         if pipepos = 1
            set p_searchtext = substr(p_searchtext, 2);
            iterate split_val_loop;
         end if;

         -- if not, do the insert for whatever is remaining and clear flag
         -- for the split_val_loop
         if pipePos = 0 then
            set str = p_searchtext;
            -- clear text since this was the end
            set p_searchtext = '';
         else
            -- there IS a pipe.  get portion UP TO, but not including the pipe
            -- do not include the pipe character in string returned
            set str = left( p_searchtext, pipePos -1);
            -- remove the entire length of the found string including the pipe
            set p_searchtext = SUBSTR( p_searchtext, pipePos +1)
         end if

         -- there HAD to be something since search text was > 0
         insert INTO split_vals VALUES (str); 
      end loop split_val_loop;

   -- I would continue ALL fetched search records and split them all first
   -- so you don't keep requerying the list as it grows for each 10 records
   end loop srchbox_loop;

   -- close cursor once out of the loop
   close srchbox_cur;

   -- uncomment below to pre-check results of split values
   -- select * from split_vals;

   -- now the next set of processing
   DECLARE alternative_search_loop_finished boolean default false; 
   DECLARE p_alternative_str VARCHAR(1000) default ''; 

   DECLARE alternative_search_cur CURSOR FOR 
      SELECT DISTINCT vals FROM  split_vals; 

   DECLARE continue HANDLER for NOT found 
      SET alternative_search_loop_finished = true; 

   OPEN alternative_search_cur; 

   alternative_search_loop : loop 
      FETCH alternative_search_cur INTO p_alternative_str; 

      IF alternative_search_loop_finished then 
         leave alternative_search_loop; 
      END IF; 

      -- select search_b 
      --    from Product_Search_Alternatives 
      --    where search_a = p_alternative_str;

      -- select p_item, p_searchtext; 

      /*
      update productsearch
      set searchbox = Concat(searchbox,' ',v_alt_txt)
      where item = v_item;        
      */
      -- select v_alt_txt;
   end loop alternative_search_loop;

   -- close cursor OUT of the loop
   close alternative_search_cur; 

-- end of procedure
end