数据库中的计算字段- Laravel

z9ju0rcb  于 2023-01-27  发布在  其他
关注(0)|答案(6)|浏览(169)

在数据库中存储计算字段的最佳做法是什么。
例如,假设一个表具有字段height、weight、bmi
用户输入身高体重值,bmi字段自动填充。如何用表单实现。
体重指数公式$体重指数=体重/(身高 * 身高)
已尝试以下配置文件模型

protected $table = 'profiles';

protected $fillable = ['user_id', 'weight', 'height', 'dob', 'age', 'bmi'];

public function user(){
  return $this->belongsTo(User::class, 'user_id');
}

protected static function boot() {
  parent::boot();

  static::saving(function($model){
      $model->bmi = $model->weight / ($model->height * $model->height);
      $model->age = (date('Y') - date('Y',strtotime($model->dob)));
  });
}

剖面控制器

public function store(Request $request)
  {
      $profile = new Profile();
      $profile->weight = $request->get('weight');
      $profile->height = $request->get('height');
      $profile->dob = $request->get('dob');
      $profile->age;
      $profile->bmi;
      $profile->save();
      return back()->with('success', 'Your profile has been updated.');
  }

但我收到一个错误

Illuminate \ Database \ QueryException (42S22)
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'weight' in 'field list' (SQL: insert into `users` (`weight`, `height`, `dob`, `bmi`, `age`, `created_by`, `updated_by`, `updated_at`, `created_at`) values (60, 175, 1988-04-03, 0.0019591836734694, 30, 2, 2, 2018-03-08 20:06:02, 2018-03-08 20:06:02))
uinbv5nw

uinbv5nw1#

您可以在模型的boot方法中执行此操作:

protected static function boot() {
    parent::boot();

    static::saving(function($model){
        $model->bmi = $model->weight / ($model->height * $model->height);
    }); 
}
mccptt67

mccptt672#

在数据库中存储计算字段的最佳做法是什么。
一般来说,不要。它是冗余的--您的数据库已经拥有计算它所需的所有信息,那么为什么还要存储冗余数据呢?
而是将an accessor放在模型上:

public function getBmiAttribute() {
    return ($this->weight / ($this->height * $this->height));
}

然后可以执行$this->bmi以获得计算值。
如果你必须在数据库中有它,使用一个Eloquent事件,你可能想挂钩到saving事件。

gtlvzcf8

gtlvzcf83#

从Laravel 5.3和MySQL 5.7开始,您可以使用列修饰符virtualAsstoredAs为MySQL创建VIRTUAL(读取行时求值)STORED(插入或更新行时求值并存储) 生成的列。
我在下面的示例中使用了virtualAs ...

Schema::create('results', function (Blueprint $table) {
        $table->bigIncrements('id');
        ...
        $table->time('predicted_time')->nullable()->default(NULL);
        $table->time('handicap')->nullable()->default(NULL);
        $table->time('finish_time')->nullable()->default(NULL);
        $table->time('actual_time')->virtualAs('TIMEDIFF(finish_time, handicap)');
        $table->time('offset')->virtualAs('TIMEDIFF(actual_time, predicted_time)');
        ...        
    });
jdzmm42g

jdzmm42g4#

在数据库中存储计算字段的最佳做法是什么。
这取决于您的用例。如果您使用的是关系数据库,并且您的用例不涉及大数据(在数量、种类或速度方面),最佳实践是不要存储计算字段,并动态计算它们。
如果您使用的是noSQL数据库(例如MongoDB,Laravel支持它)或Hadoop,最佳实践是存储计算字段以避免计算时间。

    • 简而言之**

这是时间复杂性和空间/存储复杂性之间的权衡。对于大数据/noSQL系统,存储计算字段,尤其是在计算复杂的情况下。对于关系数据库,动态计算它们,并保持数据不冗余

    • 针对RDBMS的Laravel解决方案:**

按如下方式使用访问器:

public function getBmiAttribute($value)
{
    return ($this->weight / ($this->height * $this->height));
}
    • Laravel NoSql解决方案**

按如下方式使用模型事件:

protected static function boot() {
    parent::boot();

    static::saving(function($model){
        $model->bmi = $model->weight / ($model->height * $model->height);
    }); 
}
f1tvaqid

f1tvaqid5#

如果您的DBMS支持计算列(即生成列),您可以考虑使用它们。
亮点:

  • 计算列不会将数据持久化到数据库中(或者,如果从技术上讲,它们将由DBMS管理),因此您不会复制任何数据或使任何内容冗余
  • 然后,可以在应用程序的代码库之外使用计算。例如,如果需要使用原始SQL查询开发报表,则可以在那里使用计算。
  • Eloquent(Laravel的默认ORM)将选择该列,而不需要在任何地方定义它。

您可以在迁移过程中执行代码来创建它。例如,我有一个用例,我想简化确定某个内容当前是否已发布的过程,我是这样做的:

Schema::table('article', function (Blueprint $table) {
    $table->dateTime('published_at')->nullable();
    $table->dateTime('unpublished_at')->nullable();
});

$sql = "ALTER TABLE article ADD is_published AS CAST(CASE WHEN GETUTCDATE() BETWEEN ISNULL(published_at, '2050-01-01') AND ISNULL(unpublished_at, '2050-01-01') THEN 1 ELSE 0 END AS BIT);";
DB::connection()->getPdo()->exec($sql);

然后在从数据库中检索记录后,我可以通过简单地检查来确定它是否已发布...

if ($article->is_published) ...

如果我想从数据库中查询它,我可以很容易地做到...

SELECT * FROM article WHERE is_published = 1

注意,这个语法是针对T-SQL的,因为我的项目中的RDBMS是MSSQLServer。然而,其他流行的DBMS也有类似的特性。

ALTER TABLE dbo.产品添加零售价值AS(可用数量 * 单价 * 1.35);

更改表t1添加列c2 INT,生成的INT始终作为(c1 + 1)存储;

  • Oracle:虚拟列

ALTER TABLE emp2 ADD(收入AS(薪金+(薪金 * 佣金百分比)));
PostgreSQL似乎还不支持它,但是this SO回答提供了一个不错的解决方案。

dohp0rv5

dohp0rv56#

另一种方法是在迁移中创建一个计算列,该方法适用于所有DB:-

$table->computed ('tax','price * 0.27');

但这与MySQL数据库:-

$table->integer('tax')->virtualAs('price * 0.27')->nullable();
 $table->integer('discount')->storedAs('price - 100')->nullable();

相关问题