2015-12-10 20 views
1

我有一个有很多字段的表单,每个表单都必须作为不同的行添加到表中。集体指派问题

我的表看起来像这样:

| Category | Device |  Value | 
|----------|:-------|-------------| 
| 2  | 1 | some value | 
| 3  | 1 | other value | 
| 7  | 3 |   etc | 

的类别和设备实际上是从CategoriesDevices表的外键。它们也应该是唯一的,这意味着不能有Category: 2Device: 1两次。如果它们已经存在,则值应该更新。

类别和值被从表格中检索和它看起来像这样:

{"2":"some value","3":"other value","5":"etc","6":"something","8":"can be empty"} 

该装置还来自于数形式,但将是相同的。

现在我需要在我的数据库中输入所有内容,我正在寻找一个简单的解决方案。

但它会做大约100个查询(每个输入一个),我相信必须有更好的解决方案。

如果来自表单的值之一为空,则应该忽略它。

这是我目前工作的代码,也许可以更好地理解:

public function postSpecs(Request $request) 
    { 
     $specs = $request->except(['_token', 'deviceid']); 

     foreach($specs as $key=>$val) 
     { 
      if($val == '') continue; 
      if(Spec::where('category', $key)->where('device', $request->deviceid)->exists()) 
      { 
       $spec = Spec::where('category', $key)->where('device', $request->deviceid)->first(); 
       $spec->value = $val; 
       $spec->save(); 
      } 
      else 
      { 
       $spec = new Spec; 
       $spec->category = $key; 
       $spec->device = $request->deviceid; 
       $spec->value = $val; 
       $spec->save(); 
      } 
     } 
    } 

回答

6

使用Insert方法,如:

$model->insert([ 
    ['email' => '[email protected]', 'votes' => 0], 
    ['email' => '[email protected]', 'votes' => 0] 
]); 

参见:http://laravel.com/docs/5.1/queries#inserts

编辑:

更新到您的代码:

public function postSpecs(Request $request) 
{ 
    $specs = $request->except(['_token', 'deviceid']); 

    $data = array(); 
    foreach($specs as $key=>$val) 
    { 
     if($val == '') continue; 
     if(Spec::where('category', $key)->where('device', $request->deviceid)->exists()) 
     { 
      $spec = Spec::where('category', $key)->where('device', $request->deviceid)->first(); 
      $spec->value = $val; 
      $spec->save(); 
     } 
     else 
     { 
      $data[]['category'] = $key; 
      $data[]['device'] = $request->deviceid; 
      $data[]['value'] = $val; 
     } 
    } 

    Spec::insert($data); 
} 

虽然这并不完美,但它会为您节省很多查询。否则,您必须使用原始查询类似的信息(未经测试!):

INSERT INTO spec (id,category,device,value) VALUES (1,2,3),(4,5,6) 
ON DUPLICATE KEY UPDATE id=LAST_INSERTED_ID(id) 
+0

我忘了一些东西。如果存在,我也需要更新它。所以如果我已经有行'category:2,device:1',它应该被更新。 – Alex

+1

在雄辩中没有真正的解决方案。不幸的是,你必须使用原始查询。或者您可以搜索需要更新的所有记录并逐个更新它们并批量插入新记录。你也可以使用updateOrCreate方法。 'Model :: updateOrCreate( ['primary_key'=> 8], ['field'=>'value','another_field'=>'another value'] );' –

+0

@Alex编辑为您的代码 –

1

on duplicate key update方法,因为我觉得它理应是一个可能的解决方案,如果这是会发生很多的东西多一点信息。 ..

首先,您需要创建唯一密钥。这将强制这些列是唯一的。无论您如何处理插入,我都强烈建议添加独特的密钥。这可能有助于保持您未来的理智。

在迁移时,你会怎么做?

$table->unique(['Category', 'Device']); 

还是在普通的SQL ...

alter table category_device add unique index unique_category_device (Category, Device); 

我们插入表中,您只需使用查询..

insert into category_device (Category, Device, Value) values ($category_id, $device_id, $value) 
    on duplicate key udpate Value = VALUES(Value) 

如果它不是重复的条目,mysql会直接插入新记录。如果它是重复的,mysql将更新value列,尝试插入任何新值。这在性能上非常友好,因为在尝试执行插入操作之前,您不需要检查是否存在重复项,因为它在简单重复时会更简单,就像更新语句一样。这里的缺点是laravel不支持on duplicate key update,因此您需要实际编写SQL。我建议你仍然使用数据绑定,尽管这可以使它更容易一些。

$sql = "insert into category_device (`Category`, `Device`, `Value`) values (:category_id, :device_id, :value) 
      on duplicate key udpate Value = VALUES(Value)"; 

$success = \DB::insert($sql, [ 
    'category_id' => $category_id, 
    'device_id' => $device_id, 
    'value' => $value 
]); 

同时请注意,如果你有超过100个条目,你可以通过他们循环和不断增加的查询,它应该工作一样的...

insert into category_device (`Category`, `Device`, `Value`) 
    values 
(1, 1, 'some value'), (1, 2, 'some other value'), (1, 3, 'third value')... 
    on duplicate key udpate Value = VALUES(Value)"; 

如果您正在使用这个方法,我可能不会担心数据绑定,只需将值插入查询。只要确保它们事先已经正确地逃脱了。

如果您有一百个项目要插入,这将是200个查询(一个用于检查记录的存在,另一个用于插入/更新),这会将该200个查询变为1个查询,显然这将是一个巨大的性能收益。