Запросы, выполняющиеся бесконечно (вложенный курсор / цикл) - MySQL - PullRequest
0 голосов
/ 22 декабря 2018

Я написал этот запрос, но есть логическая ошибка, которую я не могу найти.Курсор или цикл внутри курсора работает вечно, и через некоторое время я получаю ошибку максимального числа достигнутых результатов.

Заранее спасибо.

    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 голосов
/ 22 декабря 2018

Хотя в вашей процедуре было отключено содержимое во втором блоке при поиске альтернативных совпадающих строк, я не был уверен, что вы пытаетесь получить, поэтому я оставил этот блок в основном закомментированным.

Кроме того, вы на самом деле это сделалине иметь никакого смысла с предметом, поэтому я снял его.Если вам это понадобится, я бы снова добавил переменную курсора и выбрал, но мне также нужно будет добавить столбец для вставки в таблицу 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
...