Выборка записей с фильтром по количеству связанных записей

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

Начинающие программисты, скорее всего будут решать задачу перебором. Выберут все категории, посчитают для них количество записей для каждой категории отдельно. Фильрация по количеству будет уже в скрипте.

Теоретики, без реального опыта работы в сложных проектах, будут пытаться писать один запрос, который решит эту задачу. Однако, если такой запрос попадет в реальный проект с выскокой нагрузкой, их может ждать сюрприз, когда SQL сервер откажется его выполнять с приемлемой скоростью.

Третий вариант как это можно сделать - через вложенные запросы.

На мой взгляд, лучше всего решать эту задачу через временные таблицы. Думаю, вполе можно считать это производным от вложенных запросов, и не выделять как четвертый вариант.

Решение прилагаю на Yii фреймворке первой версии, но если вы работаете с другой платформой, то вам не составит труда его адаптировать. В данном случая на первом месте стоит идея, а не реализация.

Делаю модель:

class BlogCategoryCount extends CActiveRecord
{

    public static $created = FALSE;

    public function tableName()
    {
        if (static::$created == FALSE)
        {
            Yii::app()->db->createCommand('DROP TABLE IF EXISTS {{blog_category_count}}')->execute();

            $sql = Yii::app()->db
                ->createCommand()
                ->select('t.category_id as category_id, count(t.id) as count')
                ->from('{{blog_post}} t')
                ->group('t.category_id')
                ->text;

            $sql = 'CREATE TEMPORARY TABLE {{blog_category_count}} '.$sql;

            $query = Yii::app()->db->createCommand($sql);

            $query->execute();
        }

        return '{{blog_category_count}}';
    }

    public function primaryKey()
    {
        return 'category_id';
    }

}

В модели категории описываю связь с временной таблицей:

    public function relations()
    {
        return [
            'categoryCount' => [
                self::HAS_ONE,
                'BlogCategoryCount',
                'category_id'
            ]
        ];
    }

Дополним класс модели категории служебным методом для получения количества записей в категории.

public function getCount()
{
    if ($this->categoryCount != FALSE)
    {
        return $this->categoryCount->count;
    }

    return 0;
}

При выборке данных в контроллере присоединяю модель к выборке:

$categories = BlogCategory::model()->findAll([
    'with' => 'categoryCount',
    'condition' => 'categoryCount.count>=:count',
    'params' => array(
        ':count' => 1
    )
]);
comments powered by HyperComments