雄弁なORMを使用したLaravelへの一括挿入


156

Eloquent ORMを使用してLaravelでデータベースの一括挿入を実行するにはどうすればよいですか?

Laravel:https ://stackoverflow.com/a/10615821/600516でこれを達成したいの ですが、次のエラーが発生します。

SQLSTATE [HY093]:無効なパラメーター番号:名前付きパラメーターと位置パラメーターが混在しています。


1
あなたは持っていますhas_manyあなたのモデルに関係?
PapaSmurf

1
@jonathandeyいいえ、現時点では関係がありません
フェニックスウィザード

@DavidBarker私はforループを使用してクエリ文字列を形成しようとしました。また、laravelでトランザクションを使用してみました。
phoenixwizard

@AramBhusalコードを投稿していただけませんか?私はあなたを助けるいくつかのコードをここに持っていると確信しています。
David Barker

回答:


302

そのまま使えますEloquent::insert()

例えば:

$data = array(
    array('name'=>'Coder 1', 'rep'=>'4096'),
    array('name'=>'Coder 2', 'rep'=>'2048'),
    //...
);

Coder::insert($data);

2
これはまだLaravel 4に適用されますか?
14

4
@advait:はい、まだLaravel 4に適用されます
Ola

37
Eloquent実際には触れないことに注意してください。Query\Builder@insert()メソッドの呼び出しをプロキシするだけです。Eloquentを使用して複数の行を効率的に挿入する方法はなく、一括挿入の方法もありません。
Jarek Tkaczyk

6
@CanVuralタイムスタンプを更新/作成するにはどうすればよいですか?
ミラノマハルジャン2015

3
これは1つのインサートを使用します。したがって、十分な大きさの配列があると、失敗します。
patrox

72

GTF回答を更新してタイムスタンプを簡単に更新できます

$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=>date('Y-m-d H:i:s'),
        'modified_at'=> date('Y-m-d H:i:s')
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=>date('Y-m-d H:i:s'),
         'modified_at'=> date('Y-m-d H:i:s')
       ),
    //...
);

Coder::insert($data);

更新:@Pedro Moreiraが提案したように、カーボンを使用できる日付を簡略化する

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'modified_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'modified_at'=> $now
       ),
    //...
);

Coder::insert($data);

UPDATE2:laravel 5の場合、updated_at代わりにmodified_at

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'updated_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'updated_at'=> $now
       ),
    //...
);

Coder::insert($data);

42
または、スクリプトの冒頭でCarbonを使用して$now変数を定義します$now = Carbon::now('utc')->toDateTimeString();。次に'created_at' => $now, 'updated_at' => $now、すべての挿入に使用します。
ペドロモレイラ

2
新しく挿入された行のすべてのIDを取得するにはどうすればよいですか?
akshaykumar6 2015

2
なぜ「utc」なのですか?それはプロジェクトの優先事項ですか、それとも雄弁は常に「utc」で機能しますか?
ピラット

6
「スペース対タブ」という大きな引数を開始したくありませんが、タイムスタンプをUTCで保存してください。それは後であなたに多大な苦痛を救います!ユーザーについてグローバルに考えます:)
iSS 2017年

2
私が尋ねる場合Carbon、この状況では何が最も必要ですか?何が問題になっていdate("Y-m-d H:i:s")ますか?
Ifedi Okonkwo 2018

30

これを読んでいる人は、createMany()メソッドをチェックしてください。

/**
 * Create a Collection of new instances of the related model.
 *
 * @param  array  $records
 * @return \Illuminate\Database\Eloquent\Collection
 */
public function createMany(array $records)
{
    $instances = $this->related->newCollection();

    foreach ($records as $record) {
        $instances->push($this->create($record));
    }

    return $instances;
}

28
これは、いわゆる一括挿入ではありません。実装が不十分なため、この関数はアイテムごとに1回、同じクエリを準備して実行します。
Paul Spiegel

これはリレーションシップメソッドであり、モデルから直接呼び出すことはできませんModel::createMany()
掘り出し物

24

これはより雄弁な方法で行う方法です。

    $allintests = [];
    foreach($intersts as $item){ //$intersts array contains input data
        $intestcat = new User_Category();
        $intestcat->memberid = $item->memberid;
        $intestcat->catid= $item->catid;
        $allintests[] = $intestcat->attributesToArray();
    }
    User_Category::insert($allintests);

3

私はそれを何度も検索し、最終的にtimestamps以下のようなカスタムを使用しました:

$now = Carbon::now()->toDateTimeString();
Model::insert([
    ['name'=>'Foo', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Bar', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Baz', 'created_at'=>$now, 'updated_at'=>$now],
    ..................................
]);

2

Eloquent::insert 適切な解決策ですが、タイムスタンプを更新しないので、以下のようなことができます

 $json_array=array_map(function ($a) { 
                        return array_merge($a,['created_at'=> 
                                            Carbon::now(),'updated_at'=> Carbon::now()]
                                           ); 
                                     }, $json_array); 
 Model::insert($json_array);

挿入を行う前に、アレイ全体にcreated_atとupdated_atを追加するという考え方です


0

Laravel 5.7以降でIlluminate\Database\Query\Builderは、insertUsingメソッドを使用できます。

$query = [];
foreach($oXML->results->item->item as $oEntry){
    $date = date("Y-m-d H:i:s")
    $query[] = "('{$oEntry->firstname}', '{$oEntry->lastname}', '{$date}')";
}

Builder::insertUsing(['first_name', 'last_name', 'date_added'], implode(', ', $query));

-1
$start_date = date('Y-m-d h:m:s');        
        $end_date = date('Y-m-d h:m:s', strtotime($start_date . "+".$userSubscription['duration']." months") );
        $user_subscription_array = array(
          array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', ),
array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', )
        );
        dd(UserSubscription::insert($user_subscription_array));

UserSubscription私のモデル名です。正常に挿入された場合は「true」、それ以外の場合は「false」を返します。


-1

この問題を解決するためのより多くのLaravelの方法は、コレクションを使用し、タイムスタンプを利用してモデルに挿入してループすることです。

<?php

use App\Continent;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        collect([
            ['name' => 'América'],
            ['name' => 'África'],
            ['name' => 'Europa'],
            ['name' => 'Asia'],
            ['name' => 'Oceanía'],
        ])->each(function ($item, $key) {
            Continent::forceCreate($item);
        });
    }
}

編集:

私の誤解してすみません。一括挿入の場合、これが役立つ可能性があり、おそらくこれを使用すると、優れたシーダーを作成し、少し最適化できます。

<?php

use App\Continent;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $timestamp = Carbon::now();
        $password = bcrypt('secret');

        $continents = [
            [
                'name' => 'América'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'África'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Europa'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Asia'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Oceanía'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
        ];

        Continent::insert($continents);
    }
}

1
これにより、アイテムごとに1つのクエリが作成されます。一括挿入ではありません。
エミールベルジェロン2017年

1
@EmileBergeron私はあなたに同意します。私は私の投稿を編集したので、多分これは良い一括挿入に役立つかもしれません。ループから多くの時間を費やすタスク(カーボン、bcrypt)を残しておくことを考えると、これにより多くの時間を節約できます。
フランシスコダニエル

-1

カテゴリ関係の挿入では、同じ問題に遭遇し、何もわかりませんでしたが、雄弁なモデルでは、Self()を使用して、foreachに同じクラスのインスタンスを作成し、複数の保存とIDの取得を記録しました。

foreach($arCategories as $v)
{                
    if($v>0){
        $obj = new Self(); // this is to have new instance of own
        $obj->page_id = $page_id;
        $obj->category_id = $v;
        $obj->save();
    }
}

"$ obj = new Self()"がない場合、単一のレコードのみが保存されます($ objが$ thisの場合)


-4

問題は解決しました...移行のためにテーブルを変更してください

$table->timestamp('created_at')->nullable()->useCurrent();

解決:

Schema::create('spider_news', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('source')->nullable();
    $table->string('title')->nullable();
    $table->string('description')->nullable();
    $table->string('daterss')->nullable();

    $table->timestamp('created_at')->useCurrent();
    $table->timestamp('updated_at')->useCurrent();
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.