LoginSignup
5
3

More than 5 years have passed since last update.

Eloquentでjoinしたテーブルをアップデートかけようとしたらambiguousエラーがでたので調べてみた

Last updated at Posted at 2018-10-22

2つのテーブルのどちらにもupdated_atがあり、Eloquentで発行するSQLをみると
テーブルを明示的に指定できていないので下記のエラーがでている。
単純にSQLを書くとテーブル名.updated_atで解消できるが、 Eloquentを使用した際の対処法。

Column 'updated_at' in field list is ambiguous

versionとか

  • Laravel 5.5.43
  • MySQL 5.7.23

テーブルの作成

default.sql
CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `posts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `body` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

1. 一時的に自動updated_atを外し手動で現在の時間をいれる

Eloquentはupdate()やsave()を使う際、updated_atに現在の時間をいれてくれますが、一時的にその機能を外す方法。

PostController.php
    public function update(Request $request){
        $now = Carbon::now();
        $update_columns = [
            'posts.title' => 'おはようございます',
            'posts.body' => '本日も晴天なり',
            'posts.updated_at' => $now,
        ];

        $post = new Post();
        $post->timestamps = false;

        $post->join('users','users.id','=','posts.user_id')
            ->where('posts.id',$request->id)
            ->update($update_columns);
    }

2. Builder.phpのaddUpdatedAtColumn関数を書き換える

issuesを探していたら開発中の5.8で該当のPR がマージされていたので
これと同じ様に修正する。もちろんこれは自己責任になるので注意。

vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
protected function addUpdatedAtColumn(array $values)
    {
        if (! $this->model->usesTimestamps()) {
            return $values;
        }

        // return Arr::add(
        //     $values, $this->model->getUpdatedAtColumn(),
        //     $this->model->freshTimestampString()
        $column = $this->qualifyColumn($this->model->getUpdatedAtColumn());
        return array_merge(
            [$column => $this->model->freshTimestampString()],
            $values
        );
    }

3. オブジェクトをインスタンス化してから更新する

私は結局これに落ち着いた。
注意点としてselect()などでカラムを指定しないとidなどの値が上書きされていたので、カラムの制御かエイリアスが必要あり。

PostController.php
    public function update(Request $request){
        // 取得
        $post = new Post();
        $post->select('posts.*')
            ->join('users','users.id','=','posts.user_id')
            ->where('posts.id',$request->id)
            ->firstOrFail();
        // 更新
        $post->title = 'おはようございます';
        $post->body = '本日も晴天なり';
        $post->save();
    }
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3