Подтвердить что ты не робот

Яркая нетерпеливая загрузка

У меня проблема с красноречивым запросом. Я использую интенсивную загрузку (отношения "один к одному" ), чтобы получить " student". С помощью < экзамена ", используя следующий код.

Student::with('exam')->orderBy('exam.result', 'DESC')->get()

И я хочу заказать полученные строки столбцом результат экзамене. Я использую

->orderBy('exam.result', 'DESC')

Но он не работает. Любые идеи, как это сделать?

4b9b3361

Ответ 1

Попробуйте следующее:

Student::with(array('exam' => function($query) {
        $query->orderBy('result', 'DESC');
    }))
    ->get();

Ответ 2

Если вам нужно заказать коллекцию учеников по столбцу результата, вам нужно будет присоединиться к таблицам.

Student::with('exam')
       ->join('exam', 'students.id', '=', 'exam.student_id')
       ->orderBy('exam.result', 'DESC')
       ->get()

В этом случае, если у вас есть столбец student_id, и ваша таблица экзаменов будет иметь имя exam.

Ответ 3

TL;DR

Student::with('exam')->get()->sortByDesc('exam.result');

Это отсортирует результаты запроса после активной загрузки, используя методы коллекции, а не MySQL ORDER BY.

Описание

Когда вы загружаете загрузку, вы не можете использовать ORDER BY для загруженных отношений, потому что они будут запрошены и собраны в результате второго запроса. Как вы можете видеть в документации Laravel, загрузка с загрузкой происходит в 2 запросах.

Если вы хотите использовать MySQL ORDER BY, вам нужно присоединиться к связанным таблицам.

В качестве обходного решения вы можете запустить свой запрос и отсортировать полученный набор с помощью sortBy, sortByDesc или даже sort. Это решение имеет преимущества и недостатки над решением соединения:

Преимущества:

  • Вы сохраняете Eloquent функциональность.
  • Более короткий и интуитивно понятный код.

Недостатки:

  • Сортировка будет выполняться PHP вместо механизма базы данных.
  • Вы можете сортировать только по одному столбцу если вы не предоставите пользовательское закрытие функций сортировщика.
  • Если вам нужна только часть упорядоченных результатов запроса (например, ORDER BY с LIMIT), вам нужно получить все, заказать, а затем отфильтровать упорядоченный результат, иначе вы получите только (заказ не учитывает отфильтрованные элементы). Таким образом, это решение приемлемо только тогда, когда вы все равно будете работать со всем набором данных, или накладные расходы не являются проблемой.

Ответ 4

Это сработало для меня:

$query = Student::select(['id','name']);


    $query->has('exam')->with(['exam' => function ($query) {
        return $query->orderBy('result','ASC');
    }]);


    return $query->get();

Ответ 5

Вы можете использовать \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;
    }
}

Ответ 6

Существует альтернативный способ достижения результата, который вы хотите использовать без использования объединений. Вы можете сделать следующее, чтобы отсортировать учащихся по результатам их экзамена. (Laravel 5.1):

$students = Student::with('exam')->get();

$students = $students->sortByDesc(function ($student, $key)
{
    return $student->exam->result;
});