雄弁なクエリに問題があります。次のコードを使用して、「student」で「student」を取得するために、熱心な読み込み(1対1の関係)を使用しています。
Student::with('exam')->orderBy('exam.result', 'DESC')->get()
そして、受信した行を「exam」の「result」列で並べたいと思います。使っています
->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
があり、examsテーブルの名前はexam
であると仮定します。
常に試験結果でソートする場合は、モデルの関係関数にsortBy呼び出しを直接追加できます。
public function exam() {
return this->hasMany(Exam::class)->orderBy('result');
}
(この答えのクレジットはpfriendlyに送られます-彼はここで答えました: Eloquentサブクエリのソート方法 )
これは私のために働いた:
$query = Student::select(['id','name']);
$query->has('exam')->with(['exam' => function ($query) {
return $query->orderBy('result','ASC');
}]);
return $query->get();
Student::with('exam')->get()->sortByDesc('exam.result');
これは、MySQL ORDER BY
ではなく コレクションメソッド を使用して積極的にロードした後、クエリのresultsをソートします。
熱心にロードする場合、ロードされたリレーションでORDER BY
を使用することはできません。リレーションは2番目のクエリの結果として要求およびアセンブルされるためです。 Laravel documentation で見ることができるように、2つのクエリで積極的な読み込みが行われます。
MySQLのORDER BY
を使用する場合は、関連するテーブルを結合する必要があります。
回避策として、クエリを実行し、結果のコレクションを sortBy
、 sortByDesc
、または sort
。このソリューションには、結合ソリューションに比べて利点と欠点があります。
利点:
短所:
LIMIT
を含むORDER BY
)、すべてをフェッチする必要がありますeverything、それを順序付け、次に順序付けられた結果をフィルタリングします。そうしないと、フィルタリングされた部分のみが順序付けされます(順序付けは、フィルタリングされた要素を考慮しません)。したがって、このソリューションは、とにかくデータセット全体を操作する場合、またはオーバーヘッドが問題にならない場合にのみ受け入れられます。\ Illuminate\Database\Eloquent\Relations\Relationとクエリスコープを使用して、リレーションシップを通じて遠い列を追加できます。このための特性を書きました。
また、この方法は、複数の連鎖関係の深さ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;
}
}