我有一个包含很多字段的表单,每个字段都必须作为不同的行添加到表中。
我的表格如下:
| Category | Device | Value |
|----------|:-------|-------------|
| 2 | 1 | some value |
| 3 | 1 | other value |
| 7 | 3 | etc |
类别和设备实际上是Categories
和Devices
表中的外键。它们也应该是唯一的,这意味着不能有Category: 2
和Device: 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();
}
}
}
答案 0 :(得分:6)
使用插入方法,如:
$model->insert([
['email' => 'taylor@example.com', 'votes' => 0],
['email' => 'dayle@example.com', '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)
答案 1 :(得分: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个查询,这显然是一个巨大的查询绩效提升。