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