Laravel 将数据从一个表移动到另一个表并删除数据来自的列?

Posted

技术标签:

【中文标题】Laravel 将数据从一个表移动到另一个表并删除数据来自的列?【英文标题】:Laravel move data from one table to another and drop the column that the data came from? 【发布时间】:2019-10-11 20:20:27 【问题描述】:

我正在尝试在 Laravel 迁移中执行以下过程:

创建一个名为client_log_partitions 的新表。 (完成)

$table->create();

$table->bigIncrements('id')->unique();
$table->bigInteger('client_log_id');
$table->mediumText('partition_data');

$table->timestamps();

我已经有一个名为client_logs 的表,其数据存储在名为log_databigText() 列中。 client_logs 表中已存在的每一行需要每 250 KB 拆分一次(或 250,000 个字符,因为它应该是单字节编码的),然后作为分区插入到新的 client_log_partitions 表中,参考它所属的client_logs 条目。

我知道我可以使用$table->postExecute() 来实现这一点,但我只是不知道我可以用什么来做到这一点。

将数据移至新表后,我需要从client_logs 中删除log_data 列。

通常,我会使用 php 脚本或类似的东西来执行此操作。但不幸的是,我是在我无法做到的情况下进行操作的。


我的问题是,这是否可以使用 Laravel 迁移,如果可以,如何实现?

编辑

虽然我不确定,因为我只是在运行过程中完成了它并且没有对其进行测试,这就是我想象的实现这一点的 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);

【问题讨论】:

【参考方案1】:

将您的新表迁移 up 方法更改为:

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');
    );

我认为以这种方式 migrate:rollback 命令也应该可以工作(用于撤消您的更改)!

【讨论】:

我需要将来自client_logs 表的数据每 250 个字符拆分一次,然后再将其插入新表。但是,我不能使用模型来执行此操作,因为存储在旧表中的数据太大而无法一次全部加载到 PHP 中(因此首先需要此分区) 要让 migrate:rollback 工作,您必须先添加一个 down() 方法并在此处反转该过程...无论如何获取 MyOldModel::all() 本身,然后循环在它之上,应用程序内的单一创建调用对于大量数据来说非常非常耗费资源,尤其是在 PHP 中 - 你可能会杀死内存:) 我建议你不要 使用::all()-like getter 获取未定义/未知大小的数据。 关于 Laravel 中迁移数据的相关回答:***.com/a/23506744/470749【参考方案2】:

您需要做的就是运行代码来移动信息并在调用 drop column 之前重新关联 id。这是因为 up 函数中的所有内容都是按顺序运行的,从上到下,而不是异步。 https://laravel.com/docs/5.8/migrations

您可以使用 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
    

【讨论】:

现在我正试图弄清楚如何使用 SQL、查询构建器或 eloquent 一次将 250 个字符的数据移动到新表中。

以上是关于Laravel 将数据从一个表移动到另一个表并删除数据来自的列?的主要内容,如果未能解决你的问题,请参考以下文章

Lumen 将一个 db 表的数据移动到另一个 db 表

将数据从一个表复制到另一个表并更改 id [重复]

将表格行从一个表格移动到另一个表格 - AngularJS

创建触发器以将数据从一个表获取到另一个表并生成时间戳

将数据从一个表更新到另一个表并在新的 ms 访问 .net 时插入

如何将行从一个 Excel 工作表复制到另一个工作表并使用 VBA 创建重复项?