Почему в запросе 1С задваиваются документы и как это исправить?

Программист
← На главную

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

Выясним причину: почему строки дублируются?

Ключ к пониманию проблемы лежит в структуре самих документов в 1С. Большинство документов, таких как накладные, состоят из двух частей:

  1. Шапка документа: содержит общую информацию — номер, дата, контрагент, склад и т. д. Эта информация уникальна для каждого документа.
  2. Табличная часть (ТЧ): содержит список позиций — номенклатура, количество, цена, сумма по каждой строке. В одном документе может быть множество строк в табличной части.

Когда вы пишете запрос и обращаетесь напрямую к табличной части документа (например, Документ.ПоступлениеТоваровУслуг.Товары), система для каждой строки из этой табличной части формирует отдельную запись в результате запроса. При этом данные из шапки документа (например, Ссылка, Дата, Контрагент) просто копируются в каждую из этих записей.

Рассмотрим на простом примере: у вас есть документ поступления №5 от 10.05.2023, в котором две товарные позиции:

Если ваш запрос выбирает данные из табличной части "Товары", результат будет выглядеть примерно так:

| Документ | Номенклатура | Количество |
|---|---|---|
| Поступление №5 от 10.05.2023 | Стол | 2 |
| Поступление №5 от 10.05.2023 | Стул | 8 |

Как мы видим, сам документ "Поступление №5" упоминается дважды. Это не ошибка и не "задвоение" в техническом смысле. Это логичный результат работы запроса, который обрабатывает построчно табличную часть. Задача разработчика — правильно сгруппировать эти данные, чтобы получить нужный результат.

Решение 1: Группировка данных с помощью СГРУППИРОВАТЬ ПО

Это самый прямой и распространенный способ решения проблемы. Его суть заключается в том, чтобы указать запросу, по каким полям нужно объединить (сгруппировать) записи. Как правило, группировку делают по уникальному идентификатору документа — его ссылке.

При использовании группировки важно помнить правило: все поля в секции ВЫБРАТЬ, которые не указаны в секции СГРУППИРОВАТЬ ПО, должны быть обработаны агрегатными функциями.

Основные агрегатные функции:

Посмотрим на пример. Задача: получить по каждому документу поступления общую сумму и общее количество товаров.


ВЫБРАТЬ
    ПоступлениеТоваровУслугТовары.Ссылка КАК ДокументПоступления,
    СУММА(ПоступлениеТоваровУслугТовары.Сумма) КАК ОбщаяСумма,
    СУММА(ПоступлениеТоваровУслугТовары.Количество) КАК ОбщееКоличество
ИЗ
    Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары

СГРУППИРОВАТЬ ПО
    ПоступлениеТоваровУслугТовары.Ссылка

В этом запросе мы говорим системе: "Собери все строки, у которых одинаковое значение в поле Ссылка, в одну. Для каждой такой группы посчитай сумму по полю Сумма и сумму по полю Количество". В результате мы получим уникальный список документов с итоговыми показателями.

Решение 2: Предварительная агрегация во временных таблицах

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

Суть подхода в том, чтобы разбить сложный запрос на несколько простых шагов:

  1. Сначала мы создаем временную таблицу, в которой уже будут посчитаны и сгруппированы данные из табличной части.
  2. Затем мы соединяем основную таблицу (шапку документов) с этой уже подготовленной временной таблицей.

Преимущества такого подхода:

Разберем по шагам на примере:

Шаг 1. Создаем временную таблицу с итогами по товарам.


ВЫБРАТЬ
    ПоступлениеТоваровУслугТовары.Ссылка КАК Ссылка,
    СУММА(ПоступлениеТоваровУслугТовары.Сумма) КАК СуммаДокумента
ПОМЕСТИТЬ ВТ_ИтогиПоТоварам
ИЗ
    Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
СГРУППИРОВАТЬ ПО
    ПоступлениеТоваровУслугТовары.Ссылка

После выполнения этого запроса у нас в памяти появится временная таблица ВТ_ИтогиПоТоварам, содержащая две колонки: ссылку на документ и общую сумму по нему.

Шаг 2. Соединяем шапку документа с временной таблицей.


ВЫБРАТЬ
    Поступление.Ссылка,
    Поступление.Дата,
    Поступление.Контрагент,
    ВТ_ИтогиПоТоварам.СуммаДокумента
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК Поступление
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИтогиПоТоварам
        ПО Поступление.Ссылка = ВТ_ИтогиПоТоварам.Ссылка

Здесь мы берем данные из шапки документов и присоединяем к ним итоговую сумму из нашей временной таблицы. Поскольку в обеих таблицах на этом этапе каждая ссылка на документ уникальна, никакого "размножения" строк не происходит.

Этот метод особенно полезен, когда вам нужно соединить данные из табличных частей нескольких документов (например, сопоставить поступления и реализации). В этом случае для каждой табличной части создается своя временная таблица с итогами, а затем эти временные таблицы соединяются в финальном запросе.

Решение 3: Использование ключевого слова РАЗЛИЧНЫЕ

Ключевое слово РАЗЛИЧНЫЕ (аналог `DISTINCT` в SQL) просто удаляет из итогового результата все полностью идентичные строки. Этот метод может быть полезен в очень узких случаях, например, когда вам нужен просто уникальный список самих документов, которые содержат определенный товар, и вам не важны никакие итоговые данные.

Пример:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ПоступлениеТоваровУслугТовары.Ссылка
ИЗ
    Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары

Важно понимать ограничения:

В большинстве случаев правильным решением будет использование группировки.

← На главную