У меня есть база данных с полем "Инструкции" (средний текст), где каждая запись содержит параграф инструкций в виде упорядоченного списка. В настоящее время при просмотре каждый элемент списка отображается в новой строке, вызывая его с nl2br
функции PHP nl2br
.
Пример записи:
- Поместите муку, разрыхлитель и щепотку соли в миску и соедините. Отложите. 2. Поместите масло и сахар в миску и сливки с высокой скоростью до легкой и кремовой, используя насадку для весла. 3. Уменьшите микшер до умеренной скорости и постепенно добавляйте яйцо до тех пор, пока оно не будет хорошо эмульгировано. 4. Добавьте смесь муки и перемешайте, пока она не соберется вместе, чтобы сформировать тесто. Удалите тесто из смесительной чаши и поставьте между двумя листами пергамента выпечки. 5. Сверните тесто до толщины 5 мм. 6. Поместите в морозильник при предварительном нагреве духовки до 170 ° C/340 ° F. 7. Очистите пергамент и выпекайте тесто до золотистого цвета. 8. Дайте остыть, а затем храните в закрытом контейнере до тех пор, пока это не понадобится.
Как видите, в тексте есть также числа.
Я хочу разбить это одно поле на отдельную таблицу, где каждый элемент списка отдельных команд будет иметь свою собственную строку и идентификатор, связывающий его с текущим элементом.
Есть ли способ разделить мои существующие поля с MySQL? может быть разделителем "Число".
Вы можете сделать это с помощью хранимой процедуры. Это предполагает, что шаги, начинающиеся с 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 //