Как подсчитать количество документов с отбором по части наименования организации в 1С?

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке отчетов в системе 1С:Предприятие 8 часто возникает задача разделения общего потока документов на группы на основании определенных признаков контрагента или организации. Одной из типичных задач является подсчет документов, где наименование организации не содержит определенную подстроку (например, фильтрация сторонних организаций, чье имя не совпадает с внутренними подразделениями компании). Рассмотрим, как реализовать это правильно, избежав типичных ошибок производительности.

Анализ проблемы: почему стандартный подход может не работать

Разберем ситуацию, описанную в вопросе. Разработчик пытается подсчитать количество документов АрхивныйДокумент, разделяя их на «Всего» и «Сторонние». Основная сложность заключается в том, что принадлежность к «своим» определяется не по конкретной ссылке, а по вхождению слова в название организации (например, «Морошкино»).

Проанализируем основные технические препятствия, с которыми можно столкнуться при реализации такой логики:

  1. Различие типов данных: Часто программисты пытаются сравнить ссылку на справочник СправочникСсылка.Организации со строковым значением наименования. В языке запросов 1С это приведет к ошибке или неверному результату.
  2. Запрос в цикле: Это критическая ошибка («антипаттерн»). Если мы сначала получаем список организаций запросом, а потом для каждой организации запускаем новый запрос к документам, производительность системы упадет пропорционально количеству записей в базе.
  3. Неэффективное использование ПОДОБНО: Использование маски "%Текст%" отключает использование индексов СУБД, что замедляет поиск.

Решение №1: Использование условной агрегации в запросе

Наиболее эффективный способ решения задачи — использование конструкции ВЫБОР внутри агрегатной функции СУММА прямо в тексте запроса. Это позволит нам за один проход по таблице документов получить все необходимые итоговые цифры.

Рассмотрим пример кода, который решает задачу без лишних циклов и повторных обращений к базе данных:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	СУММА(1) КАК ВсегоДокументов,
    |	СУММА(ВЫБОР
    |			КОГДА НЕ АрхивныйДокумент.Организация.Наименование ПОДОБНО ""%Морошкино%""
    |				ТОГДА 1
    |			ИНАЧЕ 0
    |		КОНЕЦ) КАК СторонниеОрганизации
    |ИЗ
    |	Документ.АрхивныйДокумент КАК АрхивныйДокумент
    |ГДЕ
    |	АрхивныйДокумент.Статус = &Статус";

Запрос.УстановитьПараметр("Статус", Перечисления.Статусы.НаХранении);
Результат = Запрос.Выполнить().Выбрать();

Если Результат.Следующий() Тогда
    Сообщить("Всего: " + Результат.ВсегоДокументов);
    Сообщить("В т.ч. сторонние: " + Результат.СторонниеОрганизации);
КонецЕсли;

В данном примере мы используем объект СУММА(1) для общего подсчета и логическое условие ВЫБОР...КОНЕЦ для выделения сторонних организаций. Если условие (отсутствие слова в названии) выполняется, система прибавляет единицу, в противном случае — ноль.

Решение №2: Использование временных таблиц для фильтрации

Если нам необходимо работать со ссылками, а не со строками (что более правильно с точки зрения архитектуры 1С), мы можем сначала подготовить список «своих» организаций во временной таблице, а затем использовать его в основном расчете.

Выясним причину, почему это лучше: работа со ссылками всегда быстрее, чем постоянное обращение к строковому полю через точку Организация.Наименование в основном цикле обработки документов.

Разберем по шагам реализацию через временную таблицу:


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Шаг 1: Отбираем организации-исключения
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Организации.Ссылка КАК Ссылка
    |ПОМЕСТИТЬ ВТ_Исключения
    |ИЗ
    |	Справочник.Организации КАК Организации
    |ГДЕ
    |	Организации.Наименование ПОДОБНО ""%Морошкино%""";

Запрос.Выполнить();

// Шаг 2: Основной расчет документов
Запрос.Текст = 
    "ВЫБРАТЬ
    |	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ АрхивныйДокумент.Ссылка) КАК ОбщееКолво,
    |	СУММА(ВЫБОР
    |			КОГДА АрхивныйДокумент.Организация В (ВЫБРАТЬ Ссылка ИЗ ВТ_Исключения)
    |				ТОГДА 0
    |			ИНАЧЕ 1
    |		КОНЕЦ) КАК КолвоСторонних
    |ИЗ
    |	Документ.АрхивныйДокумент КАК АрхивныйДокумент";

Выборка = Запрос.Выполнить().Выбрать();

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

Важные замечания по оптимизации кода

Проанализируем ситуацию с «запросом в цикле», которую допустил автор темы. Когда вы пишете Пока Выборка.Следующий() Цикл... Запрос.Выполнить()... КонецЦикла, вы заставляете сервер 1С и СУБД выполнять сотни лишних сетевых пакетов и транзакций. Всегда стремитесь объединить данные в один запрос, используя ЛЕВОЕ СОЕДИНЕНИЕ или ГДЕ Организация В (...).

Также обратим внимание на обработку NULL. При использовании соединений таблиц (если вы решите соединять документы со справочником), числовые поля могут содержать пустое значение. В таких случаях обязательно используйте функцию ЕСТЬNULL(Поле, 0), чтобы избежать ошибок при арифметических операциях в коде 1С.

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

| ЕСТЬNULL(СУММА(АрхивныйДокумент.КолвоКопий), 0) КАК ВсегоКопий

Использование Системы компоновки данных (СКД)

Если ваша задача — вывести эти данные в отчет, то наиболее современным и правильным способом будет использование СКД. В компоновке данных вы можете создать вычисляемое поле. Например, поле ЭтоСторонняяОрганизация с выражением:

ВЫБОР КОГДА Организация.Наименование ПОДОБНО "%Морошкино%" ТОГДА Ложь ИНАЧЕ Истина КОНЕЦ

После этого в настройках отчета достаточно добавить ресурсы «Количество(Ссылка)» и настроить группировки. СКД сама оптимизирует запрос к базе данных и сформирует итоговую таблицу.

Подведем итог: для эффективного подсчета документов с условием по наименованию организации следует отказаться от обработки данных в цикле Пока...Цикл, использовать оператор ВЫБОР в тексте запроса для разделения счетчиков и, по возможности, предварительно фильтровать ссылки организаций через временные таблицы.

← На главную