如何提升Laravel旧查询可读性?移除CAST(SUBSTRING_INDEX)写法
优化Laravel Eloquent查询的可读性与替换CAST(SUBSTRING_INDEX)方案
一、提升查询可读性的方法
使用Eloquent模型与关联关系
定义对应模型(Game、Result、UsersTeam)并设置关联,替代直接调用DB::table,让查询逻辑更贴合业务语义:Game模型添加hasMany(Result::class)关联Result模型添加belongsTo(Game::class)和belongsTo(User::class)关联UsersTeam模型添加belongsTo(User::class)关联
拆分复杂条件,封装局部作用域
将时间、分数范围的判断逻辑封装为Game模型的局部作用域,让主查询代码更简洁,逻辑模块化。格式化代码与添加注释
保持代码缩进一致,每个查询方法单独成行,添加必要注释说明业务逻辑,降低理解成本。
二、替换CAST(SUBSTRING_INDEX)的最优方案
推荐:修改数据库结构
原写法的核心问题是将数值范围存储为-分隔的字符串,既影响查询性能,又增加代码复杂度。最优方案是拆分字段:
- 将
games表的min_max_algorithm_time拆分为min_algorithm_time(DECIMAL(10,2))和max_algorithm_time(DECIMAL(10,2)) - 将
min_max_algorithm_score拆分为min_algorithm_score(DECIMAL(10,2))和max_algorithm_score(DECIMAL(10,2))
拆分后可直接进行数值比较,无需字符串处理,性能和可读性均大幅提升。
临时方案(无法修改数据库时)
若暂时无法调整数据库结构,可将拆分逻辑封装为可复用的片段,避免重复编写冗长的CAST(SUBSTRING_INDEX)代码。
优化后的代码示例
情况1:已修改数据库结构(推荐)
// Game模型中定义局部作用域 public function scopeWithValidAlgorithmResults($query) { return $query->where(function ($q) { $q->whereNull('min_algorithm_time') ->orWhere(function ($q) { $q->whereColumn('results.time', '>=', 'games.min_algorithm_time') ->whereColumn('results.time', '<=', 'games.max_algorithm_time'); }); })->where(function ($q) { $q->whereNull('min_algorithm_score') ->orWhere(function ($q) { $q->whereColumn('results.score', '>=', 'games.min_algorithm_score') ->whereColumn('results.score', '<=', 'games.max_algorithm_score'); }); }); } // 主查询代码 Game::select('games.*') ->join('results', 'games.id', '=', 'results.game_id') ->join('users_teams', 'users_teams.user_id', '=', 'results.user_id') ->withValidAlgorithmResults() ->where('users_teams.team_id', $teamId) ->where('users_teams.is_player', 1) ->groupBy('games.id') ->get() ->toArray();
情况2:未修改数据库结构
DB::table('games AS g') ->select('g.*') ->join('results AS r', 'g.id', '=', 'r.game_id') ->join('users_teams AS ut', 'ut.user_id', '=', 'r.user_id') // 拆分时间范围条件,提升可读性 ->where(function ($query) { $query->whereNull('g.min_max_algorithm_time') ->orWhere(function ($query) { $query->whereRaw('r.time >= CAST(SUBSTRING_INDEX(g.min_max_algorithm_time, "-", 1) AS DECIMAL(10,2))') ->whereRaw('r.time <= CAST(SUBSTRING_INDEX(g.min_max_algorithm_time, "-", -1) AS DECIMAL(10,2))'); }); }) // 拆分分数范围条件 ->where(function ($query) { $query->whereNull('g.min_max_algorithm_score') ->orWhere(function ($query) { $query->whereRaw('r.score >= CAST(SUBSTRING_INDEX(g.min_max_algorithm_score, "-", 1) AS DECIMAL(10,2))') ->whereRaw('r.score <= CAST(SUBSTRING_INDEX(g.min_max_algorithm_score, "-", -1) AS DECIMAL(10,2))'); }); }) ->where('ut.team_id', $teamId) ->where('ut.is_player', 1) ->groupBy('g.id') ->get() ->toArray();
内容的提问来源于stack exchange,提问作者Mohsen
相关产品推荐
相关产品推荐

