导读:本期聚焦于小伙伴创作的《Laravel如何实现查询指定分类下未被某订单关联的分包商》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Laravel如何实现查询指定分类下未被某订单关联的分包商》有用,将其分享出去将是对创作者最好的鼓励。

在Laravel项目开发中,多表关联查询是高频需求,其中查询指定分类下未被某订单关联的分包商属于典型的5表关联去重场景,需要理清表之间的关联关系才能写出正确的查询逻辑。

Laravel如何实现查询指定分类下未被某订单关联的分包商

业务场景与表结构说明

我们先明确本次需求的业务背景,假设存在以下5张核心表,表之间的关联关系如下:

  • 分类表categories:存储分包商的分类信息,主键为id
  • 分包商表suppliers:存储分包商基础信息,主键为id,通过category_id关联分类表
  • 订单表orders:存储订单基础信息,主键为id
  • 订单分包商关联表order_supplier:存储订单和分包商的关联关系,字段为order_idsupplier_id
  • 分包商资质表supplier_qualifications:存储分包商的资质信息,通过supplier_id关联分包商表,一个分包商可能有多个资质记录

需求目标是:查询分类ID为指定值,且没有被某个指定订单ID关联的所有分包商,同时需要避免因为分包商资质表的多条记录导致分包商数据重复。

查询逻辑拆解

要实现这个需求,我们可以把查询拆解为三个核心步骤:

  1. 先筛选出指定分类下的所有分包商,关联分包商资质表,此时可能因为资质表的多条记录出现分包商重复
  2. 查询出指定订单已经关联的所有分包商ID集合
  3. 从第一步的结果中排除第二步得到的分包商ID,同时做去重处理

基础查询实现

首先我们使用Laravel的查询构造器实现基础查询逻辑,代码如下:

<?php

// 指定分类ID
$categoryId = 2;
// 指定订单ID
$orderId = 10;

// 第一步:查询指定分类下的分包商,关联资质表
$supplierQuery = DB::table('suppliers')
    ->join('categories', 'suppliers.category_id', '=', 'categories.id')
    ->leftJoin('supplier_qualifications', 'suppliers.id', '=', 'supplier_qualifications.supplier_id')
    ->where('categories.id', $categoryId);

// 第二步:查询指定订单已关联的分包商ID
$relatedSupplierIds = DB::table('order_supplier')
    ->where('order_id', $orderId)
    ->pluck('supplier_id')
    ->toArray();

// 第三步:排除已关联的分包商,去重后获取结果
$result = $supplierQuery
    ->whereNotIn('suppliers.id', $relatedSupplierIds)
    ->select('suppliers.id', 'suppliers.name', 'suppliers.contact')
    ->distinct()
    ->get();

print_r($result);

Eloquent ORM实现方式

如果项目中已经定义了对应的模型,使用Eloquent ORM可以让代码更简洁,首先定义模型关联关系:

<?php

// Supplier模型
namespace AppModels;

use IlluminateDatabaseEloquentModel;

class Supplier extends Model
{
    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id');
    }

    public function qualifications()
    {
        return $this->hasMany(SupplierQualification::class, 'supplier_id');
    }

    public function orders()
    {
        return $this->belongsToMany(Order::class, 'order_supplier', 'supplier_id', 'order_id');
    }
}

// Order模型
namespace AppModels;

use IlluminateDatabaseEloquentModel;

class Order extends Model
{
    public function suppliers()
    {
        return $this->belongsToMany(Supplier::class, 'order_supplier', 'order_id', 'supplier_id');
    }
}

基于模型实现查询的代码如下:

<?php

use AppModelsSupplier;
use AppModelsOrder;

$categoryId = 2;
$orderId = 10;

// 获取指定订单已关联的分包商ID
$order = Order::find($orderId);
$relatedSupplierIds = $order->suppliers()->pluck('suppliers.id')->toArray();

// 查询未被关联的分包商
$result = Supplier::whereHas('category', function ($query) use ($categoryId) {
        $query->where('id', $categoryId);
    })
    ->whereNotIn('id', $relatedSupplierIds)
    ->with('qualifications') // 按需加载资质关联
    ->distinct()
    ->get();

print_r($result);

去重方案说明

本次需求中需要去重的核心原因是分包商表和资质表是一对多关系,左连接资质表后,一个分包商会对应多条记录。我们使用distinct()方法对分包商的主键做去重,同时在select中只选择分包商表的字段,避免资质表的字段导致去重失效。如果查询中需要用到资质表的聚合字段,比如资质数量,可以改用groupBy('suppliers.id')的方式实现去重,代码如下:

<?php

$result = DB::table('suppliers')
    ->join('categories', 'suppliers.category_id', '=', 'categories.id')
    ->leftJoin('supplier_qualifications', 'suppliers.id', '=', 'supplier_qualifications.supplier_id')
    ->where('categories.id', 2)
    ->whereNotIn('suppliers.id', function ($query) {
        $query->select('supplier_id')
            ->from('order_supplier')
            ->where('order_id', 10);
    })
    ->select('suppliers.id', 'suppliers.name', DB::raw('count(supplier_qualifications.id) as qualification_count'))
    ->groupBy('suppliers.id', 'suppliers.name')
    ->get();

性能优化建议

针对这类多表关联查询,我们可以从以下几个方面做性能优化:

  • 给关联字段添加索引,比如suppliers.category_idorder_supplier.order_idorder_supplier.supplier_idsupplier_qualifications.supplier_id
  • 如果指定订单关联的分包商数量较多,whereNotIn可能会有性能问题,可以改用leftJoinwhereNull的方式实现排除逻辑
  • 只查询需要的字段,避免使用select *,减少数据传输和内存占用
注意:如果分包商和订单的关联关系存在软删除逻辑,需要在查询时加上软删除的过滤条件,避免查询到已经被删除的关联记录。

Laravel5表关联分包商查询去重方案订单关联修改时间:2026-06-30 23:21:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。