実現したいこと
シーダー経由で、CSVからデータベースにデータの登録を行いたい
前提
LaravelでCSVの内容をシーダー経由でMysqlに登録したいです。
しかし、シーダーを読み込ませようとするとcreated_atカラムがテーブルに存在していないかのようなエラーが出てしまいます。
発生している問題・エラーメッセージ
bash
1#docker-compose exec app bash 2root@8340ff6d38bb:/work# php artisan db:seed --class=InquiryTableSeeder 3 4 Illuminate\Database\QueryException 5 6 SQLSTATE[42S22]: Column not found: 1054 Unknown column 'created_at' in 'field list' (SQL: insert into `inquiries` (`inquiry_id`, `created_at`, `serial`, `customer`, `dealer`, `type`, `operator_id`, `questioner`, `phoneNumber`, `kinds`, `question`, `answer`, `satisfaction`, `remote`, `updated_at`, `created_at`) values (aaaaaa, 2023-03-19 00:00:00, 21555555, asdf, e, NASサーバー, 1, e, , 設定, 改行, 変更完了, 不満, TeamViewer, 2023-03-23 18:36:52, 2023-03-23 18:36:52)) 7 8 at vendor/laravel/framework/src/Illuminate/Database/Connection.php:703 9 699? // If an exception occurs when attempting to run a query, we'll format the error 10 700? // message to include the bindings with SQL, which will make this exception a 11 701? // lot more helpful to the developer instead of just the database's errors. 12 702? catch (Exception $e) { 13 ? 703? throw new QueryException( 14 704? $query, $this->prepareBindings($bindings), $e 15 705? ); 16 706? } 17 707? } 18 19 ~ A column was not found: You might have forgotten to run your migrations. You can run your migrations using `php artisan migrate`. 20 https://laravel.com/docs/master/migrations#running-migrations 21 22 +18 vendor frames 23 19 database/seeders/InquiryTableSeeder.php:94 24 Illuminate\Database\Eloquent\Model::__callStatic("updateOrCreate") 25 26 +22 vendor frames 27 42 artisan:37 28 Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
該当のソースコード
cat backend/storage/app/private/csv/inquiries_migration.csv
でCSVファイルの中身を確認するとこうなっています。
csv
1created_at,serial,customer,dealer,type,operator_id,questioner,phoneNumber,kinds,question,answer,satisfaction,inquiry_id,remote 22023-03-19 00:00:00,21555555,asdf,e,NASサーバー,1,e,,設定,改行,変更完了,不満,aaaaaa,TeamViewer
php
1//InquiryTableSeeder.php 2<?php 3 4namespace Database\Seeders; 5use Illuminate\Support\Facades\DB; 6use DateTime; 7use Illuminate\Database\Seeder; 8use App\Models\Inquiry; 9use Illuminate\Support\Arr; 10 11class InquiryTableSeeder extends Seeder 12{ 13 /** 14 * Run the database seeds. 15 * 16 * @return void 17 */ 18 public function run() 19 { 20 //ここに読み込ませたいCSV 21 $file = new \SplFileObject(storage_path('app/private/csv/inquiries_migration.csv')); 22 $file->setFlags( 23 \SplFileObject::READ_CSV | 24 \SplFileObject::READ_AHEAD | 25 \SplFileObject::SKIP_EMPTY | 26 \SplFileObject::DROP_NEW_LINE 27 ); 28 29 foreach ($file as $i => $line) { 30 if ($i === 0) { 31 $headers = $line; 32 continue; 33 } 34 35 36 // ['created_at' => 'taro'] のようにヘッダ行とデータ行を結合 37 $values = array_combine($headers, $line); 38 39 // 空白文字を含む可能性があるカラムの値から空白文字を削除 40 $values['serial'] = trim($values['serial'] ?? ''); 41 $values['type'] = trim($values['type'] ?? ''); 42 $values['phoneNumber'] = trim($values['phoneNumber'] ?? ''); 43 $values['kinds'] = trim($values['kinds'] ?? ''); 44 $values['remote'] = trim($values['remote'] ?? ''); 45 $values['satisfaction'] = trim($values['satisfaction'] ?? ''); 46 $values['operator_id'] = trim($values['operator_id'] ?? ''); 47 $values['inquiry_id'] = trim($values['inquiry_id'] ?? ''); 48 49 50 // nullか空の場合は指定の値を代入する 51 if (empty($values['kinds'])) { 52 $values['kinds'] = '設定'; 53 } 54 if (empty($values['remote'])) { 55 $values['remote'] = 'なし'; 56 } 57 if (empty($values['satisfaction'])) { 58 $values['satisfaction'] = '満足'; 59 } 60 61 if (isset($values['phoneNumber']) && !empty($values['phoneNumber'])) { 62 $phoneNumberWithoutHyphen = preg_replace('/[^0-9]/', '', $values['phoneNumber']); // 数字以外の文字列を除去 63 $values['PhoneNumberWithoutHyphen'] = $phoneNumberWithoutHyphen; 64 } 65 66 // 改行コードをリアル改行として扱う 67 $values['question'] = str_replace(['\n', '<br>'], "\n", $values['question']); 68 $values['answer'] = str_replace(['\n', '<br>'], "\n", $values['answer']); 69 70 71 // created_atカラムが存在し、空でない場合 72 if (isset($values['created_at']) && !empty($values['created_at'])) { 73 //inquiry_idが同じレコードが既にあるなら更新、なければ作成 74 Inquiry::updateOrCreate( 75 ['inquiry_id' => $values['inquiry_id']], 76 Arr::except($values, ['inquiry_id']) 77 ); 78 } else {//created_atカラムが空だったり想定されない値の場合は1970-01-01を入力 79 //$values['created_at'] = new DateTime('1970-01-01'); 80 81 //inquiry_idが同じレコードが既にあるなら更新、なければ作成 82 Inquiry::updateOrCreate( 83 ['inquiry_id' => $values['inquiry_id']], 84 Arr::except($values, ['inquiry_id']) 85 ); 86 87 } 88 } 89 90 } 91 92 }
試したこと
phpMyAdminからinquiriesテーブルを確認すると、created_atカラムはあるように見えます。
php artisan cache:clear
php artisan config:clear
サーバー再起動も行いましたが同じです。
気になる点としては、開発環境のMAC上で同じことを行ってもエラーにならないのに、
本番環境のubuntuの実機で同じことを行うとエラーになります。
本番環境にはsshに入っています。
追記
YT0014さんより指摘があった通り、
シーダー実行時のエラーに
' created_at' in 'field list' (SQL: insert into `inquiries` (`inquiry_id`, `created_at`, `serial`, `customer`, `dealer`, `type`, `operator_id`, `questioner`, `phoneNumber`, `kinds`, `question`, `answer`, `satisfaction`, `remote`, `updated_at`, `created_at`)
とのエラーから、「created_at」が複数回指定されているようです。
おそらく、csvファイル上に存在するcreated_atの値と、現在のタイムスタンプの両方を入力しようとしてしまっているのではないかと思います。
csvファイル上のcreated_atだけを使いたいのですが、何か方法はないでしょうか。
モデル側でタイムスタンプの自動挿入を無効にする方法もあるかとは思いますが、それだと影響範囲が大きいので別の方法があればありがたいです。
補足情報(FW/ツールのバージョンなど)
Docker version 23.0.1, build a5ee5b1
docker-compose version 1.29.2, build unknown
Laravel8
PHP 8.0.28 (cli) (built: Mar 1 2023 13:21:15) ( NTS )

回答2件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。