При разработке печатных форм в конфигурациях на базе 1С:Предприятие 8.3 (таких как УТ 11, ERP 2 или КА 2) программисты часто сталкиваются с эффектом «размножения» строк. Типичная ситуация: в документе есть несколько строк с одной и той же номенклатурой, а в табличной части Серии указаны данные для этих позиций. При попытке соединить эти таблицы в запросе по номенклатуре и характеристике результат внезапно увеличивается в геометрической прогрессии — количество строк получается «в квадрате». В этой статье мы подробно разберем, почему это происходит и как правильно составить запрос для корректного вывода данных.
Проанализируем ситуацию. В табличной части Товары может быть три строки с «Ботинками мужскими». В табличной части Серии также может быть три записи для этих ботинок (например, три разных серийных номера). Если мы соединяем таблицы просто ПО Номенклатура = Номенклатура, система 1С для каждой из трех строк первой таблицы найдет три соответствия во второй. В итоге мы получим 9 строк (3 * 3). Это классическое декартово произведение множеств.
Ситуация осложняется тем, что в современных конфигурациях связь между товаром и его серией не всегда очевидна. Если мы просто хотим вывести список товаров с их сериями в печатную форму, нам нужно четко сопоставить конкретную строку товара с конкретной строкой серии или же корректно сгруппировать данные.
Если ваша задача — вывести в печатную форму общие итоги по номенклатуре (без учета того, в какой именно строке документа она была введена, какая там была цена или склад), то самым простым и эффективным способом будет предварительная группировка временных таблиц. Рассмотрим этот метод по шагам.
Шаг 1. Подготовка таблицы товаров. Создаем временную таблицу ВТ_Товары, где суммируем количество в разрезе номенклатуры и характеристик.
ВЫБРАТЬ
Т.Номенклатура КАК Номенклатура,
Т.Характеристика КАК Характеристика,
СУММА(Т.Количество) КАК Количество
ПОМЕСТИТЬ ВТ_Товары
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Т
ГДЕ
Т.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
Т.Номенклатура,
Т.Характеристика;
Шаг 2. Подготовка таблицы серий. Аналогично поступаем с таблицей серий в ВТ_Серии.
ВЫБРАТЬ
С.Номенклатура КАК Номенклатура,
С.Характеристика КАК Характеристика,
С.Серия КАК Серия,
СУММА(С.Количество) КАК КоличествоСерии
ПОМЕСТИТЬ ВТ_Серии
ИЗ
Документ.РеализацияТоваровУслуг.Серии КАК С
ГДЕ
С.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
С.Номенклатура,
С.Характеристика,
С.Серия;
Шаг 3. Финальное соединение. Теперь, когда в каждой таблице уникальные ключи (Номенклатура + Характеристика), мы можем их соединить без риска дублирования.
ВЫБРАТЬ
Товары.Номенклатура,
Товары.Характеристика,
ЕСТЬNULL(Серии.Серия, ЗНАЧЕНИЕ(Справочник.СерииНоменклатуры.ПустаяСсылка)) КАК Серия,
ВЫБОР
КОГДА Серии.Серия ЕСТЬ NULL ТОГДА Товары.Количество
ИНАЧЕ Серии.КоличествоСерии
КОНЕЦ КАК Количество
ИЗ
ВТ_Товары КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Серии КАК Серии
ПО Товары.Номенклатура = Серии.Номенклатура
И Товары.Характеристика = Серии.Характеристика;
Важный нюанс: этот метод идеально подходит, когда в документе нет цен, сумм или когда они не важны для данной печатной формы (например, для расходного ордера или ТТН без цен).
Рассмотрим более сложную и правильную с точки зрения архитектуры типовых решений ситуацию. В таких конфигурациях, как 1С:ERP или 1С:Управление торговлей 11, существует специальное поле — КлючСвязи. Это числовой идентификатор, который жестко связывает строку в ТЧ Товары со строкой (или несколькими строками) в ТЧ Серии.
Проанализируем преимущества этого подхода. Если пользователь ввел одну и ту же номенклатуру в две разные строки (например, с разными ценами или под разные заказы), то у каждой строки будет свой уникальный КлючСвязи. В таблице серий для каждой серии также будет указан КлючСвязи той строки товара, к которой она относится.
Посмотрим на пример запроса с использованием этого поля:
ВЫБРАТЬ
Т.Номенклатура,
Т.Характеристика,
Т.Количество КАК КоличествоТовара,
С.Серия,
С.Количество КАК КоличествоСерии,
Т.Цена
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Серии КАК С
ПО Т.Ссылка = С.Ссылка
И Т.КлючСвязи = С.КлючСвязи
ГДЕ
Т.Ссылка = &Ссылка;
При таком соединении дублирование исключено, так как связь идет по уникальному внутри документа ключу. Если для одной строки товара указано несколько серий, вы получите ровно столько строк, сколько серий указано, и данные о товаре (цена, количество) будут корректно соотнесены.
Проанализируем ситуацию, когда политика учета серий предполагает их «справочное» указание. В этом случае в таблице Серии данных может не быть вовсе, или количество в сериях может не совпадать с общим количеством товара. Чтобы печатная форма не «потеряла» данные, рекомендуем использовать следующую логику в выражениях запроса:
ЕСТЬNULL(Серии.Количество, Товары.Количество). Если запись в сериях существует, берем количество оттуда, если нет — используем общее количество из строки товара.СтрСоединить() при выводе области макета.Разберем основные выводы нашего исследования:
КлючСвязи. Соединение по этому полю — самый надежный способ избежать математических ошибок в запросе.Товары, дополнительная таблица Серии вам вообще не понадобится — данные уже на месте.Следуя этим правилам, мы добьемся того, что наши печатные формы будут работать быстро, а данные в них всегда будут точными и не содержать «лишних» строк.