在 Laravel 迁移文件中检查列是否存在

64

我已经有一个名为table_one的表。现在我想向它添加两列。到目前为止,一切都很顺利。但是在我的方法中,我想检查表中是否存在某列,例如:dropIfExists('table')

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::table('table_one', function (Blueprint $table) {
        $table->string('column_one')->nullable();
        $table->string('column_two')->nullable();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::table('table_one', function (Blueprint $table) {
        // in here i want to check column_one and column_two exists or not
        $table->dropColumn('column_one');
        $table->dropColumn('column_two');
    });
}
7个回答

150

你需要的就是这样的东西

  public function down()
    {
        if (Schema::hasColumn('users', 'phone'))
        {
            Schema::table('users', function (Blueprint $table)
            {
                $table->dropColumn('phone');
            });
        }
    }

4
谢谢,您的解决方案效果很好。但我不太喜欢这种方法,我希望能使用像dropIfExists('column')这样的方式。 - Md.Sukel Ali
不要忘记安装doctrine/dbal包。 - prog_24

13
你可以创建自己的“dropColumnIfExists()”函数来检查列是否存在,然后删除它:
function myDropColumnIfExists($myTable, $column)
{
    if (Schema::hasColumn($myTable, $column)) //check the column
    {
        Schema::table($myTable, function (Blueprint $table)
        {
            $table->dropColumn($column); //drop it
        });
    }

}

并在“down()”函数中像这样使用:

public function down()
{
    myDropColumnIfExists('table_one', 'column_two');
    myDropColumnIfExists('table_one', 'column_one');
}

请始终提供一些解释,而不仅仅是一段代码。 - pouria
1
此时在 $table->dropColumn($column) 语句中将会产生错误,因为您没有传递 $column 参数。应该像这样: Schema::table($myTable, function (Blueprint $table) use ($column) ..... - Alshoja

4

为了动态检查您的表格列,您可以尝试以下方法:

public function dropIfExists($table, $column)
{
    if (Schema::hasColumn($table, $column)) //check the column
    {
        Schema::table($table, function (Blueprint $table) use ($column)
        {
            $table->dropColumn($column); //drop it
        });
    }

}

3

如果您真的想要将其放在Schema::table闭包中,这是唯一整洁的方法...您需要在Blueprint中添加几个方法,或者在每个迁移中使用此模板...虽然不太美观,但一旦添加完成,您就可以定义多个条件性添加和删除,每次只需使用1行。

return new class extends Migration {
    public function up() {

        Schema::table('tblAnimal', function (Blueprint $table) {
            $exists = function (string $column) use ($table) {
                return (Schema::hasColumn($table->getTable(), $column));
            };
            $addUnlessExists = function (string $type, string $name, array $parameters = [])
                use ($table, $exists) {
                    return $exists($name) ? null : $table->addColumn($type, $name, $parameters);
                };
            $dropIfExists = function (string $column) use ($table, $exists) {
                return $exists($column) ? $table->dropColumn($column) : null;
            };

            $dropIfExists('column_name');
            $addUnlessExists('integer', 'int_column');
            # ...
        });

1
你应该添加一个像这样的函数。
public function dropColumnIfExists($tbl,$column)
{
    if (Schema::hasColumn($tbl, $column)) {
        Schema::table($tbl, function (Blueprint $table) use ($column) {
            $table->dropColumn($column);
        });
    }
}

并在向上或向下函数中像这样调用它(视为向上函数)

public function up()
{
    $tbl = 'table_name';
    Schema::table($tableName, function (Blueprint $table) use ($tbl) {
        $this->dropColumnIfExists($tbl,'your_colomn_name');
    });
}

0
很棒的讨论!这里有一个可调用的方法,支持多个数据库。
使用Trait来保持DRY和干净:
namespace App\Support\Concerns;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;

trait HasManyConnections
{

    /**
     * Runs a migration conditionally if specified columns do not already exist
     *
     * @param string $connection
     *
     * @param string $table
     * @param mixed $columns
     * @param callable $callback
     *
     * @return void
     */
    function runIfColumnsAreNew(string $connection, string $table, $columns, callable $callback) : void
    {
        $schema = Schema::connection($connection);
        
        /*----------------------------------------------------------------------------
        | Create the table and run the migration if the table doesn't exist
        ----------------------------------------------------------------------------*/

        if(!$schema->hasTable($table)){

            $schema->create($table, function (Blueprint $table) use ($callback){

                $callback($table);
            });

            return;
        }

        /*----------------------------------------------------------------------------
        | Iterate the provided columns and determine if any exist
        ----------------------------------------------------------------------------*/

        $migratable = true;

        Collection::wrap($columns)->each(function($column) use ($schema, $table, &$migratable){

            if($migratable){

                $migratable = !$schema->hasColumn($table, $column);
            }
        });

        /*----------------------------------------------------------------------------
        | Update the table if all columns are new
        ----------------------------------------------------------------------------*/

        if ($migratable) {

            $schema->table($table, function (Blueprint $table) use ($callback){

                $callback($table);
            });
        }
    }
}

现在我们将其视为标准迁移,将我们的逻辑传递给闭包函数。
use App\Support\Concerns\HasManyConnections;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    use HasManyConnections;

    /**
     * Run the migrations.
     */
    public function up(): void
    {
        $this->runIfColumnsAreNew('accounts_db', 'profiles', 'squad_name', function(Blueprint $table){
           
            $table->string('squad_name')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        //
    }
};

希望有所帮助!

-14

将模式分成两个调用

public function up()
{
    Schema::table('table_one', function (Blueprint $table) {
        $table->dropColumn(['column_one', 'column_two']);
    });

    Schema::table('table_one', function (Blueprint $table) {
        $table->string('column_one')->nullable();
        $table->string('column_two')->nullable();
    });
}

11
这将导致这些列中的所有数据也被删除!非常危险的代码! - Moe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接