Laravel Eloquent跨库查询SAP B1库存数据重复问题求助
问题修复方案
核心问题说明
你查询出现重复数据的直接原因是使用了crossJoin交叉连接生成笛卡尔积,同时存在两个配置错误:
- 模型关联类型定义错误:OITW(物料库存表)和OITM(物料主表)不存在多对多关系,不需要中间表,属于直接的外键关联
- 缺少目标SQL中要求的OWHS(仓库主表)关联,没有按照内连逻辑写查询条件
第一步:修正模型定义
1. 新增仓库主表模型
新建app/Models/Warehouse.php对应SAP的OWHS仓库主表:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; class Warehouse extends Model { use HasFactory; protected $connection = 'sqlsrv2'; protected $table = 'OWHS'; }
2. 修改Almacen模型(对应OITW库存表)
替换原有错误的多对多关联,改为正确的归属关联:
class Almacen extends Model { use HasFactory; // 关联单条物料数据 public function item() { return $this->belongsTo(Stock::class, 'ItemCode', 'ItemCode'); } // 关联单条仓库数据 public function warehouse() { return $this->belongsTo(Warehouse::class, 'WhsCode', 'WhsCode'); } protected $connection = 'sqlsrv2'; protected $table = 'OITW'; }
3. 修改Stock模型(对应OITM物料主表)
替换原有错误的多对多关联,改为正确的一对多关联:
class Stock extends Model { use HasFactory; // 关联该物料在所有仓库的库存记录 public function stockRecords() { return $this->hasMany(Almacen::class, 'ItemCode', 'ItemCode'); } protected $connection = 'sqlsrv2'; protected $table = "OITM"; }
第二步:替换控制器查询代码
完全匹配你给出的目标SQL逻辑,废弃crossJoin改用内连接,从OITW表作为主表发起查询,避免数据重复:
$stock = Almacen::select( 'OITW.WhsCode', 'OWHS.WhsName', 'OITW.OnHand', 'OITM.ItemCode', 'OITM.ItemName' ) ->join('OWHS', 'OITW.WhsCode', '=', 'OWHS.WhsCode') ->join('OITM', 'OITW.ItemCode', '=', 'OITM.ItemCode') ->orderBy('OITW.WhsCode') // 按需添加过滤条件即可,示例: // ->where('OITW.OnHand', '>', 0) // ->where('OITW.WhsCode', '01') ->get(); return view('stock.index', compact('stock'));
关键说明
- 你之前用的
crossJoin会对两张表的数据做全量笛卡尔积匹配,哪怕后续加了ItemCode相等的条件,只要关联条件有遗漏就会产生和仓库数量一致的重复数据,用join(内连接)会严格按照关联字段匹配,不会产生多余重复行。 - SAP B1的OITW表本身就是物料+仓库维度的库存表,不需要用多对多关联,直接通过ItemCode关联OITM、WhsCode关联OWHS即可,完全符合你给出的原生SQL逻辑。
内容的提问来源于stack exchange,提问作者Cesar Castillo
相关产品推荐
相关产品推荐

