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