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