Ответ 1
Попробуйте следующее:
Student::with(array('exam' => function($query) {
$query->orderBy('result', 'DESC');
}))
->get();
У меня проблема с красноречивым запросом. Я использую интенсивную загрузку (отношения "один к одному" ), чтобы получить " student". С помощью < экзамена ", используя следующий код.
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::with('exam')->get()->sortByDesc('exam.result');
Это отсортирует результаты запроса после активной загрузки, используя методы коллекции, а не MySQL ORDER BY
.
Когда вы загружаете загрузку, вы не можете использовать ORDER BY
для загруженных отношений, потому что они будут запрошены и собраны в результате второго запроса. Как вы можете видеть в документации Laravel, загрузка с загрузкой происходит в 2 запросах.
Если вы хотите использовать MySQL ORDER BY
, вам нужно присоединиться к связанным таблицам.
В качестве обходного решения вы можете запустить свой запрос и отсортировать полученный набор с помощью sortBy
, sortByDesc
или даже sort
. Это решение имеет преимущества и недостатки над решением соединения:
Преимущества:
Недостатки:
ORDER BY
с 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;
});