При разработке отчетов и аналитических выборок в среде 1С программисты часто сталкиваются с задачей подсчета количества документов на основе определенных условий в их табличных частях. Например, нам необходимо узнать, сколько документов Заказ клиента содержат в строках товаров определенные варианты обеспечения (такие как "Отгрузить", "К обеспечению" и т.д.), а также получить общую статистику по всей базе данных.
Начинающие разработчики часто совершают в этой задаче критические ошибки, которые приводят либо к неверным результатам, либо к катастрофическому падению производительности системы. В этой статье мы подробно разберем типичные ошибки, проанализируем причины их возникновения и рассмотрим правильные, оптимизированные способы решения задачи с помощью языка запросов и Системы компоновки данных (СКД).
Прежде чем перейти к правильным алгоритмам, давайте разберем, как делать нельзя, и почему популярные на форумах решения часто оказываются ошибочными.
Ошибка №1: Использование простых функций СУММА(1) или КОЛИЧЕСТВО() без учета уникальности
Если мы напишем простой запрос к табличной части Документ.ЗаказКлиента.Товары и применим группировку по варианту обеспечения с подсчетом количества строк, СУБД вернет нам количество строк табличной части, а не количество документов. Если в одном заказе клиента добавлено 5 разных товаров с действием "Отгрузить", то система посчитает этот документ 5 раз. В результате итоговые цифры в отчете будут завышены в несколько раз.
Ошибка №2: Получение вложенных таблиц в запросе
Попытка использовать конструкции вида ЗаказКлиента.Товары.(КОЛИЧЕСТВО(ВариантОбеспечения)) крайне неэффективна. Использование круглых скобок для обращения к табличной части внутри запроса заставляет платформу формировать тяжелые вложенные выборки. Это существенно перегружает СУБД, усложняет чтение кода и делает невозможным дальнейший анализ данных в СКД.
Ошибка №3: Избыточные соединения (JOIN) в запросе
Часто для наложения фильтра по шапке документа (например, по статусу или дате) разработчики вручную связывают таблицу товаров с таблицей шапки документа через ЛЕВОЕ СОЕДИНЕНИЕ. В 1С это считается плохим тоном и избыточным действием. Платформа самостоятельно оптимизирует обращения через точку (например, ЗаказКлиентаТовары.Ссылка.Статус) на уровне СУБД, делая код более лаконичным и быстрым.
---
Рассмотрим ситуацию, когда нам необходимо быстро получить количество уникальных заказов клиентов в разрезе каждого варианта обеспечения, исключая при этом документы с определенным статусом (например, "Закрыт").
Чтобы избежать дублирования документов, в которых одно и то же действие встречается на нескольких строках товаров, мы должны использовать агрегатную функцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка). Разберем этот запрос подробнее:
ВЫБРАТЬ
ЗаказКлиентаТовары.ВариантОбеспечения КАК Действие,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ЗаказКлиентаТовары.Ссылка) КАК КоличествоДокументов
ИЗ
Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
ГДЕ
НЕ ЗаказКлиентаТовары.Ссылка.Статус = &Статус
СГРУППИРОВАТЬ ПО
ЗаказКлиентаТовары.ВариантОбеспечения
Как это работает:
Документ.ЗаказКлиента.Товары.ГДЕ мы фильтруем данные по статусу документа шапки через точку: ЗаказКлиентаТовары.Ссылка.Статус. Это избавляет нас от ручного написания соединений.РАЗЛИЧНЫЕ внутри функции КОЛИЧЕСТВО гарантирует, что каждый уникальный идентификатор (ссылка на документ) будет учтен в разрезе конкретной группировки только один раз.---
Что делать, если задача сложнее? Например, нам нужно вывести единую таблицу со следующей статистикой:
Для решения такой задачи оптимально использовать механизм Временных Таблиц (ВТ). Это позволит разбить сложный алгоритм на простые шаги, распределить нагрузку на сервер и получить гарантированно точный результат на больших базах данных.
Проанализируем пошагово структуру такого запроса:
// ШАГ 1: Отбираем все уникальные заказы по нужному фильтру во временную таблицу
ВЫБРАТЬ РАЗЛИЧНЫЕ
ЗаказКлиента.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ВсеЗаказы
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ГДЕ
НЕ ЗаказКлиента.Статус = &Статус
;
// ШАГ 2: Собираем уникальные заказы, в которых заполнены варианты обеспечения
ВЫБРАТЬ РАЗЛИЧНЫЕ
ЗаказКлиентаТовары.Ссылка КАК Ссылка,
ЗаказКлиентаТовары.ВариантОбеспечения КАК Действие
ПОМЕСТИТЬ ВТ_ЗаказыСДействиями
ИЗ
Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
ГДЕ
НЕ ЗаказКлиентаТовары.Ссылка.Статус = &Статус
И НЕ ЗаказКлиентаТовары.ВариантОбеспечения ЕСТЬ NULL
;
// ШАГ 3: Получаем итоговые агрегированные показатели совмещением данных
ВЫБРАТЬ
(ВЫБРАТЬ КОЛИЧЕСТВО(Ссылка) ИЗ ВТ_ВсеЗаказы) КАК ОбщееКоличествоДокументов,
(ВЫБРАТЬ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Ссылка) ИЗ ВТ_ЗаказыСДействиями) КАК ДокументовСДействиями,
ДействияДокументов.Действие КАК Действие,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДействияДокументов.Ссылка) КАК КоличествоПоДействию
ИЗ
ВТ_ЗаказыСДействиями КАК ДействияДокументов
СГРУППИРОВАТЬ ПО
ДействияДокументов.Действие
Преимущества данного подхода:
---
Если ваша конечная цель — построение пользовательского отчета, то писать сложные вложенные агрегации в тексте запроса не требуется. Система компоновки данных (СКД) берет на себя всю математику подсчета итогов, если правильно настроить ресурсы.
Выясним, как настроить такую схему за 3 простых шага:
Шаг 1. Пишем максимально простой запрос для получения детальных записей:
ВЫБРАТЬ
ЗаказКлиентаТовары.Ссылка КАК Заказ,
ЗаказКлиентаТовары.ВариантОбеспечения КАК ВариантОбеспечения
ИЗ
Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
ГДЕ
НЕ ЗаказКлиентаТовары.Ссылка.Статус = &Статус
Шаг 2. Настраиваем вкладку "Ресурсы":
Переходим на вкладку "Ресурсы" в конструкторе схемы компоновки данных. Добавляем поле Заказ в список ресурсов. В колонке "Выражение" пишем строго следующую формулу:
Количество(Различные Заказ)
Это заставит СКД на всех уровнях группировок производить вычисление только по уникальным ссылкам документов.
Шаг 3. Настраиваем структуру отчета:
В настройках компоновки добавляем группировку по полю ВариантОбеспечения. При формировании отчета СКД автоматически:
Таким образом, использование возможностей СКД — это самый надежный, быстрый и гибкий метод разработки подобных отчетов в 1С.