การแทรกจำนวนมากใน Laravel โดยใช้ eloquent ORM


156

เราจะทำการแทรกฐานข้อมูลจำนวนมากใน Laravel โดยใช้ Eloquent ORM ได้อย่างไร

ฉันต้องการทำสิ่งนี้ให้สำเร็จใน Laravel: https://stackoverflow.com/a/10615821/600516 แต่ฉันได้รับข้อผิดพลาดดังต่อไปนี้

SQLSTATE [HY093]: หมายเลขพารามิเตอร์ไม่ถูกต้อง: พารามิเตอร์ที่มีชื่อและตำแหน่งผสม


1
คุณมีhas_manyความสัมพันธ์กับนางแบบของคุณหรือไม่?
PapaSmurf

1
@ jonathandey ไม่ฉันไม่ได้มีความสัมพันธ์ใด ๆ ในขณะนี้
phoenixwizard

@DavidBarker ฉันได้ลองสร้างสตริง quesr โดยใช้ for for loop ฉันได้ลองใช้ธุรกรรมเป็น laravel แล้ว
phoenixwizard

@AramBhusal คุณสามารถโพสต์รหัสของคุณได้หรือไม่ ฉันแน่ใจว่าฉันมีรหัสที่นี่ที่จะช่วยคุณ
David Barker

คุณเคยเห็นlaravel.com/docs/database/eloquent#mass-assignmentหรือไม่
BenjaminRH

คำตอบ:


302

Eloquent::insert()คุณก็สามารถใช้

ตัวอย่างเช่น:

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

Coder::insert($data);

2
สิ่งนี้ยังใช้กับ Laravel 4 หรือไม่?
advait

4
@advait: ใช่มันยังใช้กับ Laravel 4
Ola

37
น่าสังเกตว่ามันไม่ได้สัมผัสEloquentจริง มันเป็นเพียงการเรียกQuery\Builder@insert()วิธีการ ไม่มีวิธีการแทรกหลายแถวอย่างมีประสิทธิภาพด้วย Eloquent และไม่มีวิธีการใด ๆ สำหรับการแทรกจำนวนมาก
Jarek Tkaczyk

6
@CanVural เราควรทำอย่างไรเพื่อปรับปรุง / สร้างการประทับเวลาด้วย?
Milan Maharjan

3
นี้จะใช้หนึ่งแทรก ดังนั้นเมื่อมีอาร์เรย์ขนาดใหญ่พอมันจะล้มเหลว
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
หรือใช้คาร์บอนในการเริ่มต้นของสคริปต์การกำหนดตัวแปร$now $now = Carbon::now('utc')->toDateTimeString();จากนั้นใช้'created_at' => $now, 'updated_at' => $nowสำหรับการแทรกทุกครั้ง
Pedro Moreira

2
เราจะรับ ID ทั้งหมดของแถวที่แทรกใหม่ได้อย่างไร
akshaykumar6

2
ทำไม 'utc' มันเป็นความนิยมของโครงการหรือไม่พูดเก่งทำงานใน 'utc'?
pilat

6
ฉันไม่ต้องการเริ่มอาร์กิวเมนต์ "ช่องว่างกับแท็บ" ขนาดใหญ่ แต่โปรดบันทึกการประทับเวลาใน UTC! มันจะช่วยให้คุณประหยัดความเจ็บปวดจำนวนมากในภายหลัง! คิดเกี่ยวกับผู้ใช้ทั่วโลก :)
iSS

2
ถ้าฉันจะถามสิ่งที่จำเป็นสำหรับCarbonสถานการณ์นี้คืออะไร? มีอะไรผิดปกติกับdate("Y-m-d H:i:s")?
Ifedi Okonkwo

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
นี่ไม่ใช่สิ่งที่เรียกว่าการแทรกจำนวนมาก เนื่องจากการใช้งานไม่ดีฟังก์ชันนี้จะจัดเตรียมและดำเนินการแบบสอบถามเดียวกันหนึ่งครั้งต่อรายการ
Paul Spiegel

มันเป็นมูลค่า noting Model::createMany()นี้เป็นวิธีการที่ความสัมพันธ์จะไม่สามารถเรียกได้โดยตรงจากรูปแบบคือ
digout

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

ฉันค้นหาหลายครั้งในที่สุดก็ใช้ Custom ตาม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คุณสามารถใช้วิธีการแทรกการใช้

$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เป็นชื่อรุ่นของฉัน สิ่งนี้จะคืนค่า "จริง" ถ้าการแทรกสำเร็จเป็นอย่างอื่น "เท็จ"


-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);
        });
    }
}

แก้ไข:

ขอโทษด้วยที่ฉันเข้าใจผิด สำหรับการแทรกจำนวนมากสิ่งนี้สามารถช่วยและบางทีด้วยสิ่งนี้คุณสามารถสร้าง seeders ที่ดีและเพิ่มประสิทธิภาพได้เล็กน้อย

<?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
สิ่งนี้ทำให้หนึ่งแบบสอบถามต่อรายการ มันไม่ใช่การแทรกจำนวนมาก
Emile Bergeron

1
@EmileBergeron ฉันเห็นด้วยกับคุณ ฉันได้แก้ไขโพสต์ของฉันดังนั้นนี่อาจช่วยให้มีการแทรกจำนวนมากได้ เมื่อพิจารณาจากการทิ้งงานที่ใช้เวลานานในการวนซ้ำ (คาร์บอน, bcrypt) สิ่งนี้สามารถช่วยคุณประหยัดเวลาได้มาก
Francisco Daniel

-1

สำหรับการแทรกความสัมพันธ์ของหมวดหมู่ฉันเจอปัญหาเดียวกันและไม่มีความคิดยกเว้นว่าในโมเดลของฉันฉันใช้ Self () เพื่อให้มีอินสแตนซ์ของคลาสเดียวกันใน foreach เพื่อบันทึกรหัสบันทึกและหยิบรหัสหลายรายการ

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 = ใหม่ Self ()" มันจะบันทึกเพียงบันทึกเดียว (เมื่อ $ obj คือ $ นี้)


-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.