Я пытаюсь выполнить следующий процесс миграции Laravel:
Создайте новую таблицу под названием client_log_partitions. (ГОТОВО)
$table->create();
$table->bigIncrements('id')->unique();
$table->bigInteger('client_log_id');
$table->mediumText('partition_data');
$table->timestamps();
client_logs с данными, хранящимися в столбце bigText() с именем log_data.client_logs, необходимо разделить каждые 250 КБ (или 250 000 символов, поскольку она должна быть закодирована одним байтом), а затем вставить в новую таблицу client_log_partitions как разделы со ссылкой на запись client_logs, которой она принадлежит.Я знаю, что могу добиться этого с помощью $table->postExecute(), но я просто не знаю, что я мог бы использовать для этого.
После перемещения данных в новую таблицу мне нужно удалить столбец log_data из client_logs.
Обычно я делаю это с помощью PHP-скрипта или чего-то подобного. Но, к сожалению, я работаю в обстоятельствах, когда не могу этого сделать.
Мой вопрос: возможно ли это с помощью Laravel Migrations, и если да, то как?
РЕДАКТИРОВАТЬ:
Хотя я не уверен, так как я сделал это только на лету и не тестировал его, я представляю, как SQL для достижения этого будет выглядеть примерно так:
DROP PROCEDURE IF EXISTS PROCESS_LOG_DATA;
DROP PROCEDURE IF EXISTS PROCESS_LOG_ENTRIES;
DELIMITER ;;
## Procedure for processing a specific log entry
## and moving its data to the new table.
CREATE PROCEDURE PROCESS_LOG_DATA(log_id bigint, partition_size int)
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT LENGTH(log_data)/partition_size FROM client_logs where id=log_id INTO n;
SET i=0;
WHILE i<n DO
# Move the characters to the new table.
INSERT INTO client_log_partitions
(client_log_id, partition_data)
SELECT (id, LEFT(log_data, partition_size))
FROM client_logs
WHERE id=log_id
# Shift the characters off of the log_data
UPDATE client_logs
SET log_data = SUBSTR(
log_data,
partition_size,
LENGTH(log_data) - partition_size
) where id=log_id;
# Update the number of data partitions we've processed for this log entry
SET i = i + 1;
END WHILE;
End;
;;
## Procedure for processing all log entries
## and passing each one to the PROCESS_LOG_DATA procedure.
CREATE PROCEDURE PROCESS_LOG_ENTRIES(partition_size int)
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM client_logs INTO n;
SET i=0;
WHILE i<n DO
PROCESS_LOG_DATA(i, partition_size)
END WHILE;
End;
;;
DELIMIETER ;
## Process the log entries.
CALL PROCESS_LOG_ENTRIES(250000);






Все, что вам нужно сделать, это запустить свой код, чтобы переместить информацию и повторно связать идентификаторы перед вызовом столбца удаления. Это связано с тем, что все в функции up выполняется последовательно, сверху вниз, а не асинхронно. https://laravel.com/docs/5.8/миграции
Вы можете использовать Eloquent и PHP для перемещения информации и ее изменения. Сделать это, вероятно, будет проще, чем написать запрос. Именно так компании, в которых я работал, перемещали данные, а затем изменяли таблицы. Иногда из-за глупости соответствия SoX нам приходилось перемещать данные с помощью сценариев SQL, но вам не нужно беспокоиться об этом, как это звучит.
class DropClientLogsLogDataColumn extends Migration
{
public function up()
{
// move data
$this->moveData()
Schema::table('client_logs', function (Blueprint $table) {
// drop the log_data column
$table->dropColumn('log_data');
});
}
private function moveData()
{
// do whatever you need to do here
// more than likely you'll use eloquent or query builder
// this is where you'd associate the id's
}
}
Измените новый метод переноса таблиц вверх на:
public function up()
{
//Create the table
Schema::create('your_table_name', function (Blueprint $table) {
$table->bigIncrements('id')->unique();
$table->bigInteger('client_log_id');
$table->mediumText('partition_data');
$table->timestamps();
});
//Copy column from last table to new table
foreach(MyOldModel::all() as $item)
{
//now you can save old data into new table old data : $item -> log_data
//other operation you want
MyNewModel::create(array('partition_data' => $item -> log_data));//you can save other columns with adding array values
}
//Drop old table column
Schema::table('client_logs', function (Blueprint $table) {
$table->dropColumn('log_data');
});
}
Я думаю, таким образом также должна работать команда миграция: откат (для отмены ваших изменений)!
Мне нужно разделить данные, поступающие из таблицы client_logs, каждые 250 символов, прежде чем вставлять их в новую таблицу. Однако я не могу сделать это с помощью модели, поскольку данные, хранящиеся в старой таблице, слишком велики, чтобы загрузить их все сразу в PHP (отсюда и необходимость этого разделения в первую очередь)
чтобы миграция: откат работал, вам нужно сначала добавить метод down() и отменить процесс там... в любом случае, получить MyOldModel::all(), а затем зациклиться на нем и вызвать однократное создание в приложении очень, очень ресурсоемко для больших сумм данных, особенно в PHP - вы, вероятно, убьете память :), и я бы посоветовал вам нет использовать ::all()-подобные геттеры для данных с неопределенным/неизвестным размером.
связанный ответ о данных миграции в Laravel: stackoverflow.com/a/23506744/470749
Прямо сейчас я пытаюсь понять, как я буду перемещать данные по 250 символов за раз в новую таблицу, используя SQL, построитель запросов или красноречивый.