MySQL在Yii2迁移时抛出错误,在PhpMyAdmin中没有

时间:2015-11-18 08:01:12

标签: mysql yii2

在我的一次迁移中,我向所有表添加了一个“dateCreated”列。这适用于大多数表,但在其中一些表上引发了一个奇怪的错误:

'SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect date value: '0000-00-00' for column 'start_date' at row 1 The SQL being executed was: ALTER TABLE付款ADD {dateCreated会{1}}

列'start_date'已经存在,但我无法理解为什么这与新创建的列有关。 这打破了我的迁移。直接在PhpMyAdmin中的表上应用时,相同的SQL工作正常。 Yii是否为查询添加了额外的检查,或者我错过了其他内容?

这是完整的迁移:

DATETIME NULL DEFAULT NULL'

1 个答案:

答案 0 :(得分:1)

迁移过程中存在一些错误。

1)迁移应该与数据库结构和与添加时间相关的数据进行交互,而非当前时间。

当你这样写:

Yii::$app->db->schema->tableNames;

您指的是迁移时的所有现有表。

因此,想象一下,如果稍​​后添加一些新表,并且某些表不需要该列。如果您的新队友将运行迁移或将在新服务器上运行,则dateCreated将添加到所有表中。如果是其他操作,例如删除,则可能导致严重问题,例如意外数据丢失。

请记住 - 始终使用与创建迁移时刻相关的数据库结构和数据。

我建议创建私有静态数组,并在up()down()方法中使用它。

private static $_tableNames = [
    'tableName1',
    'tableName2',
];

2)当有很多查询时,将它更安全地包装在事务中。请改用safeUp()safeDown()方法。在这种情况下,如果某些查询的迁移失败,则将应用回滚,您不必对数据库进行任何其他手动操作。

3)在迁移过程中无需为此类常见任务编写原始SQL。使用yii\db\Migration方法。

4) yii\db\Command query()用于选择,删除使用execute()。但不需要使用它,因为在执行原始SQL的迁移中存在快捷方式:$this->execute('YOUR SQL GOES HERE')

5)我建议在列名中使用非核心(_)作为分隔符,但这并不重要。

所以最后你的迁移看起来像这样:

use yii\db\Expression;
use yii\db\Migration;

class m111111_111111_add_date_created_column_to_all_existing_tables extends Migration
{
    /**
     * @var array List of table names
     */
    private static $_tableNames = [
        'tableName1',
        'tableName2',
    ],

    public function safeUp()
    {   
        foreach (self::$_tableNames as $table) {
            $this->addColumn($table, 'date_created', $this->dateTime()->defaultValue(new yii\db\Expression('NULL')));
        }
    }

    public function safeDown()
    {   
        foreach (self::$_tableNames as $table) {
            $this->dropColumn($table, 'date_created');
        }
    }
}

这更像是代码审核,但回到主要问题:在提供的代码中根本没有添加dateCreated列(实际上根本没有更改)以及与{{{{}相关的错误1}}来自不同的部分。

此类查询的逻辑:

start_date

是正确的,因此ALTER TABLE payments ADD dateCreated DATETIME NULL DEFAULT NULL 列将添加到所有列出的表名中。

现有行将填充dateCreated个数据(NULL列),因此不会出现像dateCreated这样的值(也就是日期时间,而不是日期)。 0000-00-00是一个不同的列,在其他代码处检查与之相关的逻辑。