如何将原生 SQL 查询转换为 Laravel Eloquent 查询构建器

星萱小哥_6732

星萱小哥_6732

2026-07-11

138人浏览

原创

如何将原生 SQL 查询转换为 Laravel Eloquent 查询构建器

本文详解如何将含子查询、关联统计与条件过滤的原生 sql 转换为可维护、可读性强的 laravel eloquent 写法,涵盖关系定义、withcount()、wherehas() 及模型作用域(scopes)的最佳实践。

本文详解如何将含子查询、关联统计与条件过滤的原生 sql 转换为可维护、可读性强的 laravel eloquent 写法,涵盖关系定义、withcount()、wherehas() 及模型作用域(scopes)的最佳实践。

在 Laravel 开发中,将原生 SQL 迁移至 Eloquent 或 Query Builder 不仅提升代码可维护性,更能充分利用框架的自动关联、软删除、作用域等特性。以下以你提供的原始 SQL 为例,逐步完成专业级重构。

✅ 第一步:补全缺失的关系定义

你当前的 Server 和 User 模型已定义多对多关系(server_users),但原始 SQL 中还涉及 server_user_cancellations 表的计数逻辑,因此需补充 一对多 关系(因每条 cancellation 记录属于一个 Server):

// app/Models/Server.php
public function users()
{
    return $this->belongsToMany(User::class, 'server_users');
}

// 新增:一对多关系(一个 Server 可有多个 cancellation 记录)
public function cancellations()
{
    return $this->hasMany(ServerUserCancellation::class);
}
// app/Models/User.php
public function servers()
{
    return $this->belongsToMany(Server::class, 'server_users');
}
// 注意:无需额外定义 cancellations 关系,因统计目标是「当前用户在某 Server 下是否有 cancellation」,由 Server 端反查更自然

⚠️ 提示:确保已创建 ServerUserCancellation 模型(如未创建,请运行 php artisan make:model ServerUserCancellation),并设置对应表名和主键:

protected $table = 'server_user_cancellations';

✅ 第二步:使用 whereHas() 替代 IN (SELECT ...) 子查询

原始 SQL 中的 WHERE s.id IN (SELECT server_id FROM server_users WHERE user_id = ?) 是典型的「存在关联用户」逻辑,Eloquent 提供 whereHas() 完美替代:

->whereHas('users', fn ($q) => $q->where('user_id', auth()->id()))

该语句会自动生成内连接 + 条件,语义清晰且避免 N+1。

✅ 第三步:用 withCount() 替代相关子查询统计

原始 SQL 中的 (SELECT count(id) FROM server_user_cancellations WHERE server_id = s.id AND user_id = ?) as exist 是典型的「按关联条件统计数量」场景。Eloquent 的 withCount() 支持闭包定制条件,并支持别名映射:

->withCount(['cancellations as exist' => fn ($q) => $q->where('user_id', auth()->id())])

执行后,每个 Server 实例将自动附加 exist 属性(整型,即匹配的 cancellation 数量)。

Laravel
Laravel

避免常见的Laravel错误:N+1查询、批量赋值、缓存陷阱及队列序列化陷阱。

下载

✅ 第四步:整合过滤条件,启用软删除与作用域优化

原始 SQL 包含三个关键过滤:

  • s.is_active = true
  • s.is_installed = true(注意:你的迁移中未定义该字段,请确认是否遗漏;若存在,需添加)
  • s.deleted_at IS NULL

Laravel 的 SoftDeletes trait 可自动处理 deleted_at,而 local scopes 则让业务条件复用更优雅:

// app/Models/Server.php
use Illuminate\Database\Eloquent\SoftDeletes;

class Server extends Model
{
    use SoftDeletes; // 自动排除软删除记录,无需手动 whereNull('deleted_at')

    protected $fillable = ['name', 'ip', 'username', 'is_active', 'is_installed'];

    // 本地作用域
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    public function scopeInstalled($query)
    {
        return $query->where('is_installed', true);
    }
}

? 验证:请检查 servers 表迁移中是否包含 is_installed 字段。若尚未添加,执行迁移:

php artisan make:migration add_is_installed_to_servers_table

并在 up() 方法中添加 $table->boolean('is_installed')->default(false);

✅ 最终 Eloquent 查询(控制器中)

use App\Models\Server;

$servers = Server::active()
    ->installed()
    ->whereHas('users', fn ($q) => $q->where('user_id', auth()->id()))
    ->withCount(['cancellations as exist' => fn ($q) => $q->where('user_id', auth()->id())])
    ->select('id', 'name', 'ip') // 显式指定字段,避免加载冗余列
    ->get();

// 返回 JSON 响应(适配 $request->wantsJson())
return response()->json($servers);

? 输出结构说明

结果集合中每个 Server 对象将包含:

{
  "id": 1,
  "name": "SM",
  "ip": "192.168.1.100",
  "exist": 2   // 当前用户在该 Server 下的 cancellation 记录数(0 表示不存在)
}

✅ 进阶建议

  • 性能优化:若数据量大,可在 server_user_cancellations(server_id, user_id) 和 server_users(server_id, user_id) 上添加复合索引。
  • API 封装:将上述查询提取为 Server 模型的静态方法(如 forCurrentUser()),进一步提升复用性。
  • 类型安全:配合 Laravel 9+ 的 PHP 8.1+ 属性类型声明与返回类型提示,增强 IDE 支持与可维护性。

通过以上重构,你不仅完成了 SQL 到 Eloquent 的精准转换,更构建了符合 Laravel 最佳实践、易于测试与扩展的业务逻辑层。

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

9524

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

5741

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2055

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3588

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4274

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3331

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

4757

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3722

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11722

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
如何安装 Composer
如何安装 Composer

共1课时 | 194人学习

Composer手册
Composer手册

共0课时 | 0人学习