Mysql Разделить упорядоченный список на несколько строк - PullRequest
0 голосов
/ 22 мая 2018

У меня есть база данных с полем «Инструкции» (средний текст), где каждая запись содержит параграф инструкций в виде упорядоченного списка.В настоящее время при просмотре каждый элемент списка отображается в новой строке, вызывая его с помощью функции PHP nl2br.

Пример записи:

  1. Помещение муки, выпечкапорошок и щепотку соли в миске и объединить.Отложить в сторону.2. Поместите масло и сахар в миску миксера и сливки на высокой скорости до легкого и кремового состояния, используя насадку для лопатки.3. Уменьшите миксер до умеренной скорости и постепенно добавляйте яйцо до полного эмульгирования.4. Добавить мучную смесь и перемешать до образования теста.Выньте тесто из миски и положите между 2 листами пергамента.5. Раскатать тесто до толщины 5 мм.6. Поместите в морозильник, предварительно разогрев духовку до 170 ° C / 340 ° F.7. Снимите пергамент и запекайте тесто до золотистого цвета.8. Дайте остыть, затем храните в запечатанном контейнере до тех пор, пока он не понадобится.

Как видите, в тексте также есть числа.

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

Можно ли разделить существующие поля с помощью MySQL?может ли «число» быть разделителем.

1 Ответ

0 голосов
/ 22 мая 2018

Вы можете сделать это с помощью хранимой процедуры.Предполагается, что шаги начинаются с 1, нумеруются последовательно и все выглядят как номер шага, за которым следует точка, пробел, а затем текст шага (именно так выглядит пример данных).Это должно быть достаточно легко изменить, чтобы работать с немного другими форматами.Я заставил процедуру создать набор результатов шагов, однако вы также можете изменить SELECT на INSERT, чтобы скопировать шаги в новую таблицу.

DELIMITER //
DROP PROCEDURE IF EXISTS split_recipe //
CREATE PROCEDURE split_recipe(IN recipe VARCHAR(2048))
BEGIN
  DECLARE step INT DEFAULT 1;
  DECLARE next_step INT DEFAULT step+1;
  DECLARE this_step VARCHAR(256);
  WHILE recipe RLIKE CONCAT('^[[:blank:]]*', step, '[[.period.]]') DO
    -- is there a next step?
    IF recipe RLIKE CONCAT('^[[:blank:]]*', step, '[[.period.]] .*', next_step, '[[.period.]]') THEN
      SET this_step = SUBSTRING_INDEX(SUBSTRING_INDEX(recipe, CONCAT(next_step, '. '), 1), CONCAT(step, '. '), -1);
    ELSE
      SET this_step = SUBSTRING_INDEX(recipe, CONCAT(step, '. '), -1);
    END IF;
    -- output this step
    SELECT step, this_step;
    -- remove this step from the recipe
    SET recipe = SUBSTRING_INDEX(recipe, CONCAT(step, '. ', this_step), -1);
    SET step = next_step;
    SET next_step = step + 1;
  END WHILE;
END //

С примерами данных:

CALL split_recipe('1. Place the flour, baking powder and a pinch of salt in a bowl and combine. Set aside. 2. Place the butter and sugar in a mixer bowl and cream at high speed until light and creamy, using the paddle attachment. 3. Reduce the mixer to a moderate speed and gradually add the egg until well emulsified. 4. Add the flour mixture and mix until it comes together to form a dough. Remove the dough from the mixing bowl and place between 2 sheets of baking parchment. 5. Roll the dough to a thickness of 5mm. 6. Place in the freezer while preheating the oven to 170°C/340°F. 7. Peel off the parchment and bake the dough until golden. 8. Allow to cool, then store in a sealed container until needed.')

Вывод:

step    this_step   
1       Place the flour, baking powder and a pinch of salt in a bowl and combine. Set aside. 
2       Place the butter and sugar in a mixer bowl and cream at high speed until light and creamy, using the paddle attachment. 
3       Reduce the mixer to a moderate speed and gradually add the egg until well emulsified. 
4       Add the flour mixture and mix until it comes together to form a dough. Remove the dough from the mixing bowl and place between 2 sheets of baking parchment. 
5       Roll the dough to a thickness of 5mm. 
6       Place in the freezer while preheating the oven to 170°C/340°F. 
7       Peel off the parchment and bake the dough until golden. 
8       Allow to cool, then store in a sealed container until needed.

Обратите внимание, что эта процедура создает несколько результирующих наборов из одной строки (по одному для каждого шага - я скомбинировал их для удобства чтения выше).Если требуется только один набор результатов, процедуру необходимо будет изменить, чтобы сохранить шаги во временной таблице, а затем извлечь все данные из временной таблицы в конце.В качестве альтернативы в приложении можно использовать такой код (для PHP / PDO / MySQL):

$result = $link->query("call split_recipe('1. Place the flour...')");
do {
    if ($result->columnCount()) {
        $row = $result->fetch();
        print_r($row);
    }
} while ($result->nextRowset());

Вот модифицированная версия процедуры, которая разбивает рецепты из таблицы recipes (RecipeID INT, Instructions VARCHAR(2048)) нановый стол new_recipes (RecipeID INT, step_num INT, Instruction VARCHAR(256)).

DELIMITER //
DROP PROCEDURE IF EXISTS split_recipes //
CREATE PROCEDURE split_recipes()
BEGIN
  DECLARE rid INT;
  DECLARE recipe VARCHAR(2048);
  DECLARE step INT;
  DECLARE next_step INT;
  DECLARE this_step VARCHAR(256);
  DECLARE finished INT DEFAULT 0;
  DECLARE recipe_cursor CURSOR FOR SELECT RecipeID, Instructions FROM recipes;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
  DROP TABLE IF EXISTS new_recipes;
  CREATE TABLE new_recipes (RecipeID INT, step_num INT, Instruction VARCHAR(256));
  OPEN recipe_cursor;
  recipe_loop: LOOP
    FETCH recipe_cursor INTO rid, recipe;
    IF finished = 1 THEN
      LEAVE recipe_loop;
    END IF;
    SET step = 1;
    SET next_step = 2;
    WHILE recipe RLIKE CONCAT('^[[:blank:]]*', step, '[[.period.]]') DO
      -- is there a next step?
      IF recipe RLIKE CONCAT('^[[:blank:]]*', step, '[[.period.]] .*', next_step, '[[.period.]]') THEN
        SET this_step = SUBSTRING_INDEX(SUBSTRING_INDEX(recipe, CONCAT(next_step, '. '), 1), CONCAT(step, '. '), -1);
      ELSE
        SET this_step = SUBSTRING_INDEX(recipe, CONCAT(step, '. '), -1);
      END IF;
      -- insert this step into the new table
      INSERT INTO new_recipes VALUES (rid, step, this_step);
      -- remove this step from the recipe
      SET recipe = SUBSTRING_INDEX(recipe, CONCAT(step, '. ', this_step), -1);
      SET step = next_step;
      SET next_step = step + 1;
    END WHILE;
  END LOOP;
END //
...