ActiveDataProvider joinWith и OrderBy

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
webplus
Сообщения: 245
Зарегистрирован: 2012.02.24, 22:05
Контактная информация:

ActiveDataProvider joinWith и OrderBy

Сообщение webplus » 2019.04.16, 19:59

Здравствуйте!

Код: Выделить всё

        $query = Dialog::find();
        $query->joinWith(['messageLast']);

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 20,
            ],
            'sort'=> [
                'attributes' => [
                    'user1',
                    'user2',
                    'theme',
                    'updated_at',
                    'messages.date_add'
                ],
                'defaultOrder' => [
                    'messages.date_add' => SORT_DESC,
                ]
            ],
        ]);
в модели

Код: Выделить всё

    public function getMessageLast(){
        return $this->hasOne(Message::className(), ['dialog_id' => 'id'])->orderBy('date_add DESC');
    }
Выводит в грид не 20 записей, а по 14 (на каждой странице разное количество записей).
Пробовал добавлять ->distinct() тогда выводит 20 записей как надо, но не сортирует по полю 'messages.date_add' => SORT_DESC , такая же ситуация с group by.

А если сам sql запрос ввести в консоль, то выводит как надо 20 записей с сортировкой. Наверно что то с ActiveDataProvider

Аватара пользователя
futbolim
Сообщения: 2049
Зарегистрирован: 2012.07.08, 19:28

Re: ActiveDataProvider joinWith и OrderBy

Сообщение futbolim » 2019.04.16, 20:11

$query->with(['messageLast']);
with делает аналог left join (только отдельным запросом)
joinWith делает inner join по идее

Аватара пользователя
webplus
Сообщения: 245
Зарегистрирован: 2012.02.24, 22:05
Контактная информация:

Re: ActiveDataProvider joinWith и OrderBy

Сообщение webplus » 2019.04.16, 20:30

futbolim писал(а):
2019.04.16, 20:11
$query->with(['messageLast']);
with делает аналог left join (только отдельным запросом)
joinWith делает inner join по идее
попробовал

Код: Выделить всё

        $query->innerJoinWith(['messageLast']);
но выводит в место 20 записей - 14 и сортирует как надо. Если добавить ->distinct() то 20 выводит как надо, но сортировка слетает.

Аватара пользователя
futbolim
Сообщения: 2049
Зарегистрирован: 2012.07.08, 19:28

Re: ActiveDataProvider joinWith и OrderBy

Сообщение futbolim » 2019.04.16, 20:32

Покажите тот sql запрос, который 14 выбирает

Аватара пользователя
webplus
Сообщения: 245
Зарегистрирован: 2012.02.24, 22:05
Контактная информация:

Re: ActiveDataProvider joinWith и OrderBy

Сообщение webplus » 2019.04.16, 20:36

futbolim писал(а):
2019.04.16, 20:32
Покажите тот sql запрос, который 14 выбирает

Код: Выделить всё

SELECT `dialogs`.* FROM `dialogs` INNER JOIN `messages` ON `dialogs`.`id` = `messages`.`dialog_id` ORDER BY `messages`.`date_add` DESC LIMIT 20
если его в консоль phpmyadmin-а ввести, то выводит как надо 20 записей и сортирует. А в ActiveDataProvider отдает только 14 записей

Аватара пользователя
webplus
Сообщения: 245
Зарегистрирован: 2012.02.24, 22:05
Контактная информация:

Re: ActiveDataProvider joinWith и OrderBy

Сообщение webplus » 2019.04.16, 21:06

futbolim писал(а):
2019.04.16, 20:32
Покажите тот sql запрос, который 14 выбирает
Ссори в консоли phpmyadmin запрос:

Код: Выделить всё

SELECT `dialogs`.* FROM `dialogs` INNER JOIN `messages` ON `dialogs`.`id` = `messages`.`dialog_id` ORDER BY `messages`.`date_add` DESC LIMIT 20
выдает 20 записей но с дублями, т.е. ID записи я заметил повторяются. если добавить GROUP BY `messages`.`dialog_id` к запросу то группирует
и выводит как надо 20 записей без дублей, но сортировка ORDER BY `messages`.`date_add` DESC не работает, сортирует по первому `messages`.`date_add` , а должно по последнему так как у нас DESC

вот запрос с гроуп:

Код: Выделить всё

SELECT `dialogs`.*, `messages`.`date_add` AS `m_date_add` FROM `dialogs` INNER JOIN `messages` ON `dialogs`.`id` = `messages`.`dialog_id` GROUP BY `messages`.`dialog_id` ORDER BY `m_date_add` DESC LIMIT 20

Аватара пользователя
futbolim
Сообщения: 2049
Зарегистрирован: 2012.07.08, 19:28

Re: ActiveDataProvider joinWith и OrderBy

Сообщение futbolim » 2019.04.17, 00:48

Ну а второй нормально сортирует?

Loveorigami
Сообщения: 965
Зарегистрирован: 2014.08.27, 21:54

Re: ActiveDataProvider joinWith и OrderBy

Сообщение Loveorigami » 2019.04.17, 10:33

Это датапровайдер при подготовке моделей записывает их в массив. Ключ массива - это id первичной модели.
выдает 20 записей но с дублями, т.е. ID записи я заметил повторяются.
Если у вас несколько строк с одинаковым id - они и перезаписываются в массиве датапровайдера.

Как такое получилось у вас - это вопрос архитектуры.

Иначе - чтоб вывести Все записи, вам в запрос надо добавить ->indexBy('...') с уникальным ключом, который Вы можете вытянуть запросом.

Аватара пользователя
webplus
Сообщения: 245
Зарегистрирован: 2012.02.24, 22:05
Контактная информация:

Re: ActiveDataProvider joinWith и OrderBy

Сообщение webplus » 2019.04.17, 12:37

futbolim писал(а):
2019.04.17, 00:48
Ну а второй нормально сортирует?
в версии mysql 5.7 есть странность работы с group by и order by. Об этом пишут в интернете. Пишут что mysql не дает гарантии вывода результатов при использовании group by и order by
в ранних версиях mysql тот запрос что я выше привел работает нормально, но а в этой версии отработал запрос с MAX(messages.date_add) as m_date_add в селекте
вот сам запрос:

Код: Выделить всё

SELECT `dialogs`.*, MAX(messages.date_add) as m_date_add FROM `dialogs` LEFT JOIN `messages` ON `dialogs`.`id` = `messages`.`dialog_id` GROUP BY `messages`.`dialog_id` ORDER BY `m_date_add` DESC LIMIT 20
я сделал MAX(messages.date_add) as m_date_add а потом по нему сортировку. И все работает корректно!

someweb
Сообщения: 535
Зарегистрирован: 2017.03.09, 10:12

Re: ActiveDataProvider joinWith и OrderBy

Сообщение someweb » 2019.04.17, 13:13

Это не странность MySql, при использовании GROUP BY в списке выбора должны присутствовать только поля перечисленные в GROUP BY или агрегатные функции.
Чтобы правильно задать вопрос, нужно знать бо́льшую часть ответа. Роберт Шекли.

Ответить