I'm new to Laravel and have a migration like this:
public function up()
{
Schema::table('mytable', function(Blueprint $table)
{
$table->renameColumn('mycol', 'old_mycol');
$table->string('mycol', 100);
});
}
When I run it, I get the error:
[PDOException]
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'mycol'
I ended up splitting it into 2 separate migrations and that worked fine, but I don't understand why doing it in one pass is a problem.
This is because Laravel will implicitly put any commands that add new or modify existing columns at the very beginning of the commands array when the migration is executed. The following code is taken directly from the Illuminate\Database\Schema\Blueprint
class.
/**
* Get the raw SQL statements for the blueprint.
*
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return array
*/
public function toSql(Connection $connection, Grammar $grammar)
{
$this->addImpliedCommands();
$statements = array();
// Each type of command has a corresponding compiler function on the schema
// grammar which is used to build the necessary SQL statements to build
// the blueprint element, so we'll just call that compilers function.
foreach ($this->commands as $command)
{
$method = 'compile'.ucfirst($command->name);
if (method_exists($grammar, $method))
{
if ( ! is_null($sql = $grammar->$method($this, $command, $connection)))
{
$statements = array_merge($statements, (array) $sql);
}
}
}
return $statements;
}
/**
* Add the commands that are implied by the blueprint.
*
* @return void
*/
protected function addImpliedCommands()
{
if (count($this->getAddedColumns()) > 0 && ! $this->creating())
{
array_unshift($this->commands, $this->createCommand('add'));
}
if (count($this->getChangedColumns()) > 0 && ! $this->creating())
{
array_unshift($this->commands, $this->createCommand('change'));
}
$this->addFluentIndexes();
}
As you can see from the code above, in the toSql
method, there's a call to addImpliedCommands
in which several commands might get added to the beginning of the commands array of the object. This causes the command for your new mycol
column to be executed first before the rename command.
To get around this, you don't really need to create two migrations. In the same migration, you can simply call Schema::table()
twice like so:
Schema::table('mytable', function(Blueprint $table)
{
$table->renameColumn('mycol', 'old_mycol');
});
Schema::table('mytable', function(Blueprint $table)
{
$table->string('mycol', 100);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With