mysql将有序列表拆分为多行

cczfrluj  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(379)

我有一个带有“指令”字段(mediumtext)的数据库,其中每个条目都以有序列表的形式包含一段指令。当前,在查看时,每个列表项都通过php调用显示在新行上 nl2br 功能。
示例条目:
把面粉,发酵粉和一小撮盐放在碗里混合。放在一边。2把黄油和糖放在一个搅拌碗里,用搅拌桨快速搅拌,直到奶油变轻变稠。三。把搅拌器调到中速,逐渐加入鸡蛋,直到完全乳化。4加入面粉混合物,搅拌至面团。从搅拌碗中取出面团,放在两张烤羊皮纸之间。5把面团擀成5毫米厚。6将烤箱预热至170℃时放入冰箱°公元340年°f。7剥去羊皮纸,把面团烤到金黄色。8冷却,然后储存在密封容器中直到需要。
正如你所看到的,文本中也有数字。
我想将这个字段拆分成一个单独的表,其中每个单独的指令列表项都有自己的行和id,将其链接到当前项。
有没有办法用mysql拆分现有字段?你能说出一个“数字”作为分隔符。

qaxu7uf2

qaxu7uf21#

您可以使用存储过程来实现这一点。这一个假设步骤从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)) 放进一张新table里 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 //

相关问题