Laravel迁移 - 在表中添加检查约束条件

28

我想在Laravel Migration中创建这样的表格 -

CREATE TABLE Payroll
(
 ID int PRIMARY KEY, 
 PositionID INT,
 Salary decimal(9,2) 
 CHECK (Salary < 150000.00)
);

我所做的是-

Schema::create('Payroll', function (Blueprint $table)
{
    $table->increments('id');
    $table->integer('PositionID ');
    $table->decimal('Salary',9,2);
    //$table->timestamps();
});

但我无法创建这个 -

 CHECK (Salary < 150000.00)

请问,如何在Laravel Migration中实现CHECK约束条件?


3
对于我们中的谷歌用户,Kael Watts-Deuchar的回答需要更新。截至MariaDB 10.2.1,MariaDB现在支持检查约束(check constraints)。 (由于我缺少50个声望值,无法直接评论Kael's的回答)。 - Pascal Bakhuis
6个回答

43

蓝图类不支持添加约束条件(至少在 Laravel 5.3 中是这样),但可以通过使用数据库语句直接向表中添加约束条件来实现。

在您的迁移文件中,

public function up ()
{
    Schema::create('payroll', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('position_id');
        $table->decimal('salary',9,2);
    });

    // Add the constraint
    DB::statement('ALTER TABLE payroll ADD CONSTRAINT chk_salary_amount CHECK (salary < 150000.00);');
}

1
这种方法有效,但请注意它不适用于SQLite(例如在内存数据库进行测试时)。SQLite不支持在创建表后更改约束。为了解决这个问题,您需要确保仅在除SQLite之外的任何地方添加约束。 - AngryUbuntuNerd

4
我认为Laravel migrations中没有这个功能。我认为这将成为您的模型或验证逻辑中的一部分,除非您手动将其添加到MYSQL中。
这是我的做法。
$this->validate($request, [
    'Salary' => 'max:150000.00',
]);

这也是我解决这个问题的方式。在你的控制器中使用这个函数,在你保存或更新数据之前获取请求。 - Philipp Schemel
2
我不是在询问它,我是在请求与MySQL端的自动验证,所以这并没有帮助我。但还是谢谢你尝试帮助 :) - Abrar Jahin
MySQL不支持check约束! - Yasser CHENIK
是的,它可以... https://www.w3schools.com/mysql/mysql_check.asp - Jay Bienvenu

2

这个功能不包含在Blueprint类中,因此你无法在迁移文件中执行该操作。

但是,在你的工资单模型中,你可以创建一个访问器:

class Payroll extends Model{

    public function setSalaryAttribute($value){
        $this->attributes['Salary'] = $value < 150000.00 ? $value : 150000.00;
    }

}

因此,当创建或更新薪资属性时,该方法将自动触发并检查新值是否超过150000.00

编辑:您应该查看Laravel文档中的访问器和修改器文档


你可以在迁移文件中添加约束条件,只是不能使用Blueprint类。有关详细信息,请参见我的答案 - Michael
这将悄悄地限制数量,这与CHECK CONSTRAINT的完全相反 - 抛出错误。如果您想要模仿CHECK CONSTRAINT的行为,我建议您抛出一个错误。 - Peter Chaula

1
这个答案已经过时了,MariaDB 10.2.1和MySQL 8.0.16都支持适当的检查约束。
MySQL/Mariadb忽略CHECK约束,因此必须使用触发器。触发器只能设置为在INSERT/UPDATE/DELETE中运行之一,这意味着如果我们想要它在INSERT和UPDATE上运行,我们必须创建一个过程,然后从两个单独的触发器调用它。
DB::statement()不支持此语法,因此我们必须改用PDO::exec()。
以下是Michael示例的TRIGGER语法:
public function up()
{
    Schema::create('Payroll', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('position_id');
        $table->decimal('salary', 9, 2);
    });

    DB::connection()->getPdo()->exec("
        -- Create the procedure
        CREATE PROCEDURE payroll_check_salary_amount (salary INT)
        BEGIN
            IF NOT (salary < 150000.00) THEN
                SIGNAL SQLSTATE '45000' SET message_text = 'salary must be less than 150000.00';
            END IF;
        END;

        -- Create the INSERT trigger
        CREATE TRIGGER payroll_check_salary_amount_insert BEFORE INSERT ON Payroll
        FOR EACH ROW
        BEGIN
            CALL payroll_check_salary_amount(NEW.salary);
        END;

        -- Create the UPDATE trigger
        CREATE TRIGGER payroll_check_salary_amount_update BEFORE UPDATE ON Payroll
        FOR EACH ROW
        BEGIN
            CALL payroll_check_salary_amount(NEW.salary);
        END;
    ");
}

public function down()
{
    Schema::dropIfExists('Payroll');
    DB::statement('DROP PROCEDURE IF EXISTS payroll_check_salary_amount');
}

1
在MySQL 8.0.16之前,CREATE TABLE仅允许以下有限版本的表CHECK约束语法,该语法将被解析并忽略:从MySQL 8.0.16开始,CREATE TABLE允许所有存储引擎使用表和列CHECK约束的核心功能。CREATE TABLE允许以下CHECK约束语法,用于表约束和列约束:https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html - Naveed Ali

1
要添加约束条件,您可以编写以下代码。
$table->enum('choices', ['foo', 'bar']);

但如果你想使用算术运算来实现,解决方案是使用SQL语句,正如**@Michael**所提到的。

// Add the constraint
DB::statement('ALTER TABLE payroll ADD CONSTRAINT chk_salary_amount CHECK (salary < 150000.00);');

请查看以下链接以获取更多信息


-1
public function up ()
{
    Schema::create('payroll', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('p_id');
        $table->decimal('payment',9,2);
    });

    // Add the constraint`enter code here`
    DB::statement('ALTER TABLE payroll ADD CONSTRAINT check_salary_amount CHECK (payment < 2000.00);');
}

2
请编辑您的回答并解释您的代码为何有效! - Amir Shabani

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