我对雄辩的查询有疑问。我正在使用急切加载(一对一关系)来获得“学生”和“考试”,使用下面的代码。
Student::with('exam')->orderBy('exam.result', 'DESC')->get()
我想按“考试”中的“结果”列对接收到的行进行排序。我在用
->orderBy('exam.result', 'DESC')
但它不起作用。任何想法如何做到这一点?
我对雄辩的查询有疑问。我正在使用急切加载(一对一关系)来获得“学生”和“考试”,使用下面的代码。
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
。
如果您总是希望它按考试结果排序,您可以直接在模型的关系函数中添加 sortBy 调用。
public function exam() {
return this->hasMany(Exam::class)->orderBy('result');
}
(这个答案的功劳归于 pfriendly - 他在这里回答了这个问题:How to sort an Eloquent subquery)
Student::with('exam')->get()->sortByDesc('exam.result');
这将使用集合方法而不是 MySQL对预加载后的查询结果进行排序。ORDER BY
当您急切加载时,您不能ORDER BY
在加载的关系上使用 an,因为第二次查询将请求和组装这些关系。正如您在Laravel 文档中看到的那样,急切加载发生在 2 个查询中。
如果你想使用 MySQL ORDER BY
,你必须加入相关的表。
作为一种解决方法,您可以运行查询并使用或什至对结果集合sortBy
进行排序。与join解决方案相比,此解决方案具有优点和缺点:sortByDesc
sort
优点:
缺点:
ORDER BY
with LIMIT
),则必须获取所有内容,对其进行排序,然后过滤排序结果,否则您最终将仅对过滤后的部分进行排序(排序将不考虑过滤掉的元素)。因此,仅当您无论如何都要处理整个数据集或开销不是问题时,此解决方案才可接受。这对我有用:
$query = Student::select(['id','name']);
$query->has('exam')->with(['exam' => function ($query) {
return $query->orderBy('result','ASC');
}]);
return $query->get();
您可以使用 \Illuminate\Database\Eloquent\Relations\Relation 和查询范围通过关系添加远列,我为此编写了一个特征,它错过了 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;
}
}
有一种替代方法可以在不使用连接的情况下实现您想要的结果。您可以执行以下操作以根据学生的考试结果对学生进行排序。(Laravel 5.1):
$students = Student::with('exam')->get();
$students = $students->sortByDesc(function ($student, $key)
{
return $student->exam->result;
});