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