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

Допустим у нас есть 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