×

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

Недавно столкнулся с одной задачей, решение которой в нормальном виде нигде не описано.

Описание задачи

Есть некоторое количество данных в highload блоке. Нужно подсчитать, сколько записей имеют определённые значения в некоем столбце этой таблицы (которой является HL-блок).

Поиск решения

Самое простое решение в лоб: вызываем \Bitrix\Main\Entity\DataManager::getList, получаем все записи из highload блока и подсчитываем нужные значения средствами PHP. Это вполне рабочий вариант, но медленный. Потому что тут и база данных перебирает все строки таблицы, и цикл в PHP может работать долго, если записей миллионы.

Логично было бы использовать средства d7 вроде \Bitrix\Main\Entity\DataManager::getCount, но этот метод просто возвращает количество записей для конкретного запроса. Под изначальную задачу не подходит.

Решение

Недолгим поиском по форумам и блогам было найден нужный параметр метода \Bitrix\Main\Entity\DataManager::getList, который я как-то проглядел до этого. Параметр этот называется runtime.

В этом параметре можно указать функции, которыми БД будет оперировать с данными. При этом в документации нет примера использования для этого параметра. И в коде компонентов битрикса он упоминается буквально один-два раза. Но этого достаточно.

Нам необходимо использовать SQL функцию count, для подсчета значений. И вот как это сделать с использованием D7 и без прямых запросов к БД:

$result = НазваниеКлассаУнаследованногоОтDataManager::getList([
	'filter' => ['какой-нибудь фильтр'],
	
	//тут важно указать название столбца таблицы 
	//(свойства HL блока, обычно начинающегося с UF)
	//по которому мы будем группировать отчет
	//второй элемент, это название для столбца,
	//в котором будут выведены итоговые суммы, в данном случае пусть это будет COUNT
	'select' => [
		'Название_поля_для_группировки',
		'COUNT'
	],
	
	//сортировку можно делать по столбцу с суммами
	'order' => [
		'COUNT' => 'DESC'
	],
	
	//тут мы должны указать как будет считаться столбец COUNT
	'runtime' => [
		//в качестве ключа используется поле, которое мы указали в select
		'COUNT' => [
			//тут указывается тип данных, для поля. 
			//я встречал только примеры с integer и reference
			'data_type' => 'integer',
			
			//тут указывается функция, вроде count, max и т.п.
			//важно следить за кавычками и указывать правильные имена таблицы
			//(они обычно не совпадают с названиями HL блока)
			'expression' => ['count(`имя_таблицы`.`поле_для_подсчета`)']
		]
	]
]);

В итоге мы получаем массив вида

[
	'Значение поля' => 'количество',
	...
]

Задача решена

logo