Выполнить OrderBy перед GroupBy при использовании MySQL, и Yii2

Небольшая заметка, которая может ответить не только на проблему, обозначенную в заголовке, но и продемонстрировать 3 способа построения запроса и получения результатов запросов. К сожалению, стандартно подставив команду OrderBy перед GroupBy в MySQL вы получите совсем не то что ожидаете, а происходит это потому, что выполняется сначала группировка данных, а уже затем они сортируются, но уже в результирующем наборе нет нужных нам данных, решается эта проблема в «подсовывании» новой таблицы уже с правильной для нас сортировкой, запросом это выглядит примерно так:

SELECT * 
FROM 
  (
    SELECT * 
    FROM `table` 
    ORDER BY `date` DESC
  ) as `new_table`
GROUP BY `test_id` 

В результате выполнения данного запроса мы получим сгруппированные данные по test_id новой таблицы new_table в которой мы отсортировали данные по дате. Теперь как то же самое сделать использую Yii2? Я опишу 3 возможных способа:

Выполнение sql запроса в Yii2

Думаю здесь все достаточно просто: скидываем текст запроса в переменную и выполняем команду через базовый объект:

$sql = 'SELECT * FROM ( SELECT * FROM `table` ORDER BY `date` DESC ) as `new_table` GROUP BY `test_id` ';
$result = Yii::$app->db->createCommand($sql)->queryAll();

На выходе в переменной $result получаем массив с результатами запроса

Использование конструктора запросов

Более интересным методом получения данных в нашей ситуации является использование конструктора запросов:

$result = (new Query())
  ->from([
    'new_table' => (new Query())
      ->from('table')
      ->orderBy([
        'date' => SORT_DESC
      ])
    ])
  ->groupBy('test_id')
  ->all();

Код получился компактнее и читаемее, не правда ли? Из интересного в данном куске кода пожалуй объявление двух объектов Query() и использование базовой константы SORT_DESC, а в переменной $result окажется все тот же массив данных.

Кстати, чтобы все заработало в контроллере должно быть указано:

use yii\db\Query;

Использование базовой модели

Самым верным вариантом получения результатов при решении данной задачи является использование ранее сгенерированной модели:

$result = Table::find()
  ->from([
    'new_table' => Table::find()
      ->orderBy([
        'date' => SORT_DESC
      ])
    ])
  ->groupBy('test_id')
  ->all()

После выполнения в переменной $result будет…, верно модель данных, чтобы был массив нужно использовать asArray(), о котором немного подробнее было рассказано тут. Плюс использование модели и Active Record для построения запроса это возможность подставить в запрос что-то вроде:

->with('test')

и получить кроме всего прочего соединенные данные из таблицы test.

Ах да, в контроллере должно быть:

use app\models\Table;
comments powered by HyperComments
Борис
2018-01-20 17:02:53
Не работает ... :(
ыкрерк
2018-02-01 13:59:08
вобще бред с подсовыванием новой таблице - групперовке насрать на порядок
При копировании материалов обратная ссылка на play-stop.ru желательна обязательна!