Как правильно объединить табличные части «Товары» и «Серии» в запросе, чтобы избежать дублирования строк?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке печатных форм в конфигурациях на базе 1С:Предприятие 8.3 (таких как УТ 11, ERP 2 или КА 2) программисты часто сталкиваются с эффектом «размножения» строк. Типичная ситуация: в документе есть несколько строк с одной и той же номенклатурой, а в табличной части Серии указаны данные для этих позиций. При попытке соединить эти таблицы в запросе по номенклатуре и характеристике результат внезапно увеличивается в геометрической прогрессии — количество строк получается «в квадрате». В этой статье мы подробно разберем, почему это происходит и как правильно составить запрос для корректного вывода данных.

Выясняем причину: почему строки «размножаются»?

Проанализируем ситуацию. В табличной части Товары может быть три строки с «Ботинками мужскими». В табличной части Серии также может быть три записи для этих ботинок (например, три разных серийных номера). Если мы соединяем таблицы просто ПО Номенклатура = Номенклатура, система 1С для каждой из трех строк первой таблицы найдет три соответствия во второй. В итоге мы получим 9 строк (3 * 3). Это классическое декартово произведение множеств.

Ситуация осложняется тем, что в современных конфигурациях связь между товаром и его серией не всегда очевидна. Если мы просто хотим вывести список товаров с их сериями в печатную форму, нам нужно четко сопоставить конкретную строку товара с конкретной строкой серии или же корректно сгруппировать данные.

Решение №1: Группировка данных (Сворачивание)

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

Шаг 1. Подготовка таблицы товаров. Создаем временную таблицу ВТ_Товары, где суммируем количество в разрезе номенклатуры и характеристик.


ВЫБРАТЬ
    Т.Номенклатура КАК Номенклатура,
    Т.Характеристика КАК Характеристика,
    СУММА(Т.Количество) КАК Количество
ПОМЕСТИТЬ ВТ_Товары
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК Т
ГДЕ
    Т.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    Т.Номенклатура,
    Т.Характеристика;

Шаг 2. Подготовка таблицы серий. Аналогично поступаем с таблицей серий в ВТ_Серии.


ВЫБРАТЬ
    С.Номенклатура КАК Номенклатура,
    С.Характеристика КАК Характеристика,
    С.Серия КАК Серия,
    СУММА(С.Количество) КАК КоличествоСерии
ПОМЕСТИТЬ ВТ_Серии
ИЗ
    Документ.РеализацияТоваровУслуг.Серии КАК С
ГДЕ
    С.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    С.Номенклатура,
    С.Характеристика,
    С.Серия;

Шаг 3. Финальное соединение. Теперь, когда в каждой таблице уникальные ключи (Номенклатура + Характеристика), мы можем их соединить без риска дублирования.


ВЫБРАТЬ
    Товары.Номенклатура,
    Товары.Характеристика,
    ЕСТЬNULL(Серии.Серия, ЗНАЧЕНИЕ(Справочник.СерииНоменклатуры.ПустаяСсылка)) КАК Серия,
    ВЫБОР
        КОГДА Серии.Серия ЕСТЬ NULL ТОГДА Товары.Количество
        ИНАЧЕ Серии.КоличествоСерии
    КОНЕЦ КАК Количество
ИЗ
    ВТ_Товары КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Серии КАК Серии
    ПО Товары.Номенклатура = Серии.Номенклатура
    И Товары.Характеристика = Серии.Характеристика;

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

Решение №2: Использование технического ключа связи (КлючСвязи)

Рассмотрим более сложную и правильную с точки зрения архитектуры типовых решений ситуацию. В таких конфигурациях, как 1С:ERP или 1С:Управление торговлей 11, существует специальное поле — КлючСвязи. Это числовой идентификатор, который жестко связывает строку в ТЧ Товары со строкой (или несколькими строками) в ТЧ Серии.

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

Посмотрим на пример запроса с использованием этого поля:


ВЫБРАТЬ
    Т.Номенклатура,
    Т.Характеристика,
    Т.Количество КАК КоличествоТовара,
    С.Серия,
    С.Количество КАК КоличествоСерии,
    Т.Цена
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Серии КАК С
    ПО Т.Ссылка = С.Ссылка
    И Т.КлючСвязи = С.КлючСвязи
ГДЕ
    Т.Ссылка = &Ссылка;

При таком соединении дублирование исключено, так как связь идет по уникальному внутри документа ключу. Если для одной строки товара указано несколько серий, вы получите ровно столько строк, сколько серий указано, и данные о товаре (цена, количество) будут корректно соотнесены.

Как обрабатывать ситуации, когда серий нет или они указаны частично?

Проанализируем ситуацию, когда политика учета серий предполагает их «справочное» указание. В этом случае в таблице Серии данных может не быть вовсе, или количество в сериях может не совпадать с общим количеством товара. Чтобы печатная форма не «потеряла» данные, рекомендуем использовать следующую логику в выражениях запроса:

  1. Используйте ЛЕВОЕ СОЕДИНЕНИЕ от таблицы товаров к таблице серий. Это гарантирует, что даже если серии не выбраны, сам товар попадет в отчет.
  2. Для вывода количества применяйте конструкцию ЕСТЬNULL(Серии.Количество, Товары.Количество). Если запись в сериях существует, берем количество оттуда, если нет — используем общее количество из строки товара.
  3. Если серии нужно вывести «через запятую» в одной строке, не делайте соединение в запросе. Вместо этого выгрузите серии в отдельное дерево или массив и используйте функцию СтрСоединить() при выводе области макета.

Итоги и рекомендации

Разберем основные выводы нашего исследования:

Следуя этим правилам, мы добьемся того, что наши печатные формы будут работать быстро, а данные в них всегда будут точными и не содержать «лишних» строк.

← На главную