Задача такая: вывести данные через компонент CGridView в YII, сгруппированные по определённому полю, а также применение условий по агрегированным данным.
Возьмём простую таблицу:
1
date | clicks
Нам нужно получить сгруппированные данные по каждому часу.
По сути нужно применить следующий запрос
123
SELECT*FROMtableGROUPBYLEFT(date,13);
Возникают следующие трудности в реализации через Yii:
Yii не может посчитать общее количество, а соответственно будет неправильно создавать пагинатор. Yii просто обнуляет поля group by и having при подсчёте общего количества. Да ещё count(*) тут не сработает, нужно просто. посчитать количество строк, которое вернул запрос с группировкой
Также нам не подходит использование where, чтобы искать по группированным данным. Тут нужно использовать having by.
Сортировка. Yii автоматически подставляет поле без агрегирующей функции. А если использовать отношения, то ещё и подставит алиас главной таблицы (t.clicks).
Соответственно, мы руками высчитываем общее количество и устанавливаем найденное значение в атрибут totalItemCount компонента CActiveDataProvider
publicfunctionsearch(){$criteria=newCDbCriteria;$criteria->compare('date',$this->date,true);if($this->clicks){// Скопипастил из исходников yiiif(preg_match('/^(?:\s*(<>|<=|>=|<|>|=))(.*)$/',$this->clicks,$matches)){$clicks=$matches[2];$op=$matches[1];}else{$clicks=$this->clicks;$op='=';}// Проставляем having by$criteria->having='SUM(clicks) '.$op.' '.Yii::app()->db->quoteValue($clicks);}// Выбираем дату без минут и секунд И сумму кликов за определённый час$criteria->select='LEFT(date, 13) AS date, SUM(clicks) AS clicks';// Применяем группировку по часам$criteria->group='LEFT(date, 13)';// Клонируем объект критерии, чтобы посчитать общее количество записей$countCriteria=clone$criteria;$countCriteria->select='1';$sum=count(static::model()->findAll($countCriteria));$pages=newCPagination($sum);$pages->pageSize=50;$pages->applyLimit($criteria);returnnewCActiveDataProvider(get_class($this),array('totalItemCount'=>$sum,'criteria'=>$criteria,'pagination'=>$pages,'sort'=>array('attributes'=>array(// Тут устанавливаем свою сортировку по нужному полю'clicks'=>array('asc'=>'SUM(clicks) ASC','desc'=>'SUM(clicks) DESC',)),'defaultOrder'=>'date DESC',),));}