SQLite插入时如何递增默认列值?Laravel适配问题问询
解决Laravel updateOrCreate在SQLite中递增列的报错问题
背景与现有实现
你开发了一个异常处理器来跟踪API调用的失败尝试次数,当调用失败时会用Laravel的updateOrCreate方法来更新或创建数据库记录:
try { Vmi::createPurchaseOrder($purchaseOrder); } catch (Exception $e) { PurchaseOrder::updateOrCreate( ['invoice_id' => $purchaseOrder->invoice_id], [ 'error' => $e->getMessage(), 'attempts' => DB::raw('attempts + 1'), ] ); }
对应的表结构如下:
invoice_id: unsigned interror: textattempts: unsigned int,默认值为0
这段逻辑在MySQL中运行正常,但切换到内存SQLite做测试时,抛出了如下错误:
PDOException: SQLSTATE[HY000]: General error: 1 no such column: attempts
问题根源:SQLite与MySQL的语法差异
问题出在SQLite不支持INSERT语句中引用同表的列。你给出的SQL示例很清楚:
- 下面的INSERT语句在MySQL中可行,但SQLite会报错,因为插入新记录时
attempts列还不存在,无法引用它做加法:
insert into purchase_orders ( invoice_id, error, attempts ) values ( 1, 'Invalid customer ID', attempts + 1 );
- 而UPDATE语句在SQLite中是正常的,因为此时记录已经存在,
attempts列有值可以引用:
update purchase_orders set attempts = attempts + 1 where invoice_id = 1;
Laravel的updateOrCreate方法在执行创建操作时,会把你传入的DB::raw('attempts +1')直接拼到INSERT语句里,这就触发了SQLite的语法限制。
解决方案:拆分逻辑适配SQLite
我们可以把updateOrCreate的逻辑拆分开,分别处理“更新现有记录”和“创建新记录”的场景,避免在INSERT时引用同表列:
方案一:手动判断记录是否存在
try { Vmi::createPurchaseOrder($purchaseOrder); } catch (Exception $e) { $record = PurchaseOrder::where('invoice_id', $purchaseOrder->invoice_id)->first(); if ($record) { // 记录存在,执行更新,递增attempts $record->update([ 'error' => $e->getMessage(), 'attempts' => DB::raw('attempts + 1'), ]); } else { // 记录不存在,创建新记录,attempts设为1(第一次失败) PurchaseOrder::create([ 'invoice_id' => $purchaseOrder->invoice_id, 'error' => $e->getMessage(), 'attempts' => 1, ]); } }
方案二:使用firstOrNew结合increment方法
这个方案更简洁,利用Laravel的increment方法自动适配不同数据库:
try { Vmi::createPurchaseOrder($purchaseOrder); } catch (Exception $e) { $record = PurchaseOrder::firstOrNew(['invoice_id' => $purchaseOrder->invoice_id]); $record->error = $e->getMessage(); if ($record->exists) { // 已有记录,直接递增attempts(Laravel会生成正确的UPDATE语句) $record->increment('attempts'); } else { // 新记录,设置attempts为1后保存 $record->attempts = 1; $record->save(); } }
这两种方案都能同时兼容MySQL和SQLite,解决你遇到的测试报错问题。
内容的提问来源于stack exchange,提问作者Kelly Kiernan
相关产品推荐
相关产品推荐

