我对雄辩的问题有疑问。我使用急切加载(一对一的关系) ,以获得’学生’与’考试’,使用下面的代码。
Student::with('exam')->orderBy('exam.result', 'DESC')->get()
我想通过‘ 考试’中的‘ 结果’列对接收到的行进行排序
->orderBy('exam.result', 'DESC')
但是没有用,有什么办法吗?
试试这个:
Student::with(array('exam' => function($query) { $query->orderBy('result', 'DESC'); })) ->get();
如果需要按照结果列对学生集合进行排序,则需要联接这些表。
Student::with('exam') ->join('exam', 'students.id', '=', 'exam.student_id') ->orderBy('exam.result', 'DESC') ->get()
在这种情况下,假设您有一列 student_id,并且您的考试表名为 exam。
student_id
exam
还有一种不使用联接实现您想要的结果的替代方法。您可以执行以下操作,根据学生的考试成绩对他们进行排序。(幼虫5.1) :
$students = Student::with('exam')->get(); $students = $students->sortByDesc(function ($student, $key) { return $student->exam->result; });
Student::with('exam')->get()->sortByDesc('exam.result');
这将使用 收集方法对查询的 结果进行排序,而不是使用 MySQLORDER BY。
ORDER BY
当您渴望加载时,您不能在加载的关系上使用 ORDER BY,因为这些关系将被请求并组装为第二个查询的结果。正如您在 Laravel 文档热切加载中看到的,它发生在2个查询中。
如果你想使用 MySQL 的 ORDER BY,你必须连接相关的表。
作为解决方案,您可以运行查询并使用 sortBy、 sortByDesc甚至 sort对结果集合进行排序。与联接解决方案相比,此解决方案有优点和缺点:
sortBy
sortByDesc
sort
优点:
缺点:
LIMIT
你可以使用照明数据库雄辩关系关系和查询范围添加远列通过关系,我为此写了一个特点,它错过了 HasOne o HasMany,但有 BelongsTo 和 BelongsTomany 可以很容易地适应
此外,该方法可以增强,以支持多个链接关系的深度超过1,我为此腾出了空间
<?php /** * User: matteo.orefice * Date: 16/05/2017 * Time: 10:54 */ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; trait WithFarColumnsTrait { public function scopeWithFarColumns(Builder $query , $relationPath , $columns , $tableAliasPrefix = null) { $relationPath = array_wrap($relationPath); $tableAliasPrefix = $tableAliasPrefix ?: WithFarColumnsTrait::randomStringAlpha(3); $currentModel = $this; $subQueries = []; $relationIndex = 0; foreach ($relationPath as $relationName) { if (method_exists($currentModel , $relationName)) { $relation = $currentModel->$relationName(); } else { throw new BadMethodCallException("Relationship $relationName does not exist, cannot join."); } $currentTable = $currentModel->getTable(); if ($relationIndex == 0) { $query->addSelect($currentTable . '.*'); } $relatedModel = $relation->getRelated(); /** * @var string */ $relatedTable = $relatedModel->getTable(); if ($relation instanceof BelongsTo) { foreach ($columns as $alias => $column) { $tableAlias = $tableAliasPrefix . $relationIndex; $tableAndAlias = $relatedTable . ' AS ' . $tableAlias; /** * Al momento gestisce soltanto la prima relazione * todo: navigare le far relationships e creare delle join composte */ if (!isset($subQueries[$alias])) { $subQueries[$alias] = $currentQuery = DB::query() ->from($tableAndAlias) ->whereColumn( $relation->getQualifiedForeignKey() , // 'child-table.fk-column' '=' , $tableAlias . '.' . $relation->getOwnerKey() // 'parent-table.id-column' ) ->select($tableAlias . '.' . $column); // se la colonna ha una chiave stringa e' un alias /** * todo: in caso di relazioni multiple aggiungere solo per la piu lontana */ if (is_string($alias)) { $query->selectSub($currentQuery , $alias); } else { throw new \InvalidArgumentException('Columns must be an associative array'); } } else { throw new \Exception('Multiple relation chain not implemented yet'); } } // end foreach <COLUMNs> } // endif else if ($relation instanceof BelongsToMany) { foreach ($columns as $alias => $column) { $tableAlias = $tableAliasPrefix . $relationIndex; $tableAndAlias = $relatedTable . ' AS ' . $tableAlias; if (!isset($subQueries[$alias])) { $pivotTable = $relation->getTable(); $subQueries[$alias] = $currentQuery = DB::query() ->from($tableAndAlias) ->select($tableAlias . '.' . $column) // final table vs pivot table ->join( $pivotTable , // tabelle pivot $relation->getQualifiedRelatedKeyName() , // pivot.fk_related_id '=' , $tableAlias . '.' . $relatedModel->getKeyName() // related_with_alias.id ) ->whereColumn( $relation->getQualifiedForeignKeyName() , '=' , $relation->getParent()->getQualifiedKeyName() ); if (is_string($alias)) { $query->selectSub($currentQuery , $alias); } else { throw new \InvalidArgumentException('Columns must be an associative array'); } } else { throw new \Exception('Multiple relation chain not implemented yet'); } } // end foreach <COLUMNs> } else { throw new \InvalidArgumentException( sprintf("Relation $relationName of type %s is not supported" , get_class($relation)) ); } $currentModel = $relatedModel; $relationIndex++; } // end foreach <RELATIONs> } /** * @param $length * @return string */ public static function randomStringAlpha($length) { $pool = array_merge(range('a', 'z'),range('A', 'Z')); $key = ''; for($i=0; $i < $length; $i++) { $key .= $pool[mt_rand(0, count($pool) - 1)]; } return $key; } }
这对我很有效:
$query = Student::select(['id','name']); $query->has('exam')->with(['exam' => function ($query) { return $query->orderBy('result','ASC'); }]); return $query->get();
如果您总是希望它按照考试结果排序,那么可以直接在模型的关系函数中添加 sortBy 调用。
public function exam() { return this->hasMany(Exam::class)->orderBy('result'); }
(这个问题的答案归功于 pfriends-他在这里回答了: 如何对 Eloquent 子查询排序)