Как добавить колонку из регистра в запрос для печатной формы табличной части

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке печатных форм в 1С часто возникает задача дополнить стандартные данные табличной части документа информацией из других источников: регистров сведений, справочников или констант. Рассмотрим, как правильно объединить эти данные в одном запросе, чтобы избежать дублирования строк и обеспечить корректный вывод даже при отсутствии записей в дополнительных таблицах.

Разбор основной проблемы: выбор типа соединения

В сообщениях форума автор изначально пытался использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN) для связи табличной части документа СписокТМЦ и регистра ДанныеПоТМЦ. Проанализируем, почему это критическая ошибка для печатной формы.

Внутреннее соединение оставляет в результате только те строки, которые есть в обеих таблицах. Если для какой-то номенклатуры в регистре «ДанныеПоТМЦ» не заполнена запись, то вся строка из документа просто исчезнет из печатной формы. Это недопустимо для официальных документов.

Для решения этой задачи необходимо использовать ЛЕВОЕ СОЕДИНЕНИЕ. Оно гарантирует, что все строки из основной таблицы (табличной части документа) попадут в результат, а данные из регистра подтянутся только там, где они есть. Если данных в регистре нет, поля будут заполнены значением NULL.

Оптимизация структуры запроса: объединение шапки и табличной части

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


// Запрос для шапки
Запрос1.Текст = "ВЫБРАТЬ Выбытие.Дата, Константа.Организация КАК Организация... ГДЕ Ссылка = &Ссылка";

// Запрос для строк
Запрос2.Текст = "ВЫБРАТЬ ТЧ.Номенклатура, ТЧ.Количество, Регистр.Поле... ГДЕ ТЧ.Ссылка = &Ссылка";

Такой подход требует двойного обращения к базе данных и усложняет код обхода выборок. Проанализируем более эффективный метод — использование одного запроса с конструкцией ИТОГИ ПО. Это позволит получить и данные шапки, и данные строк за один раз.

Проектирование универсального запроса для печати

Разберем по шагам, как составить правильный текст запроса. Мы объединим данные документа, его табличной части, регистра сведений и констант.


ВЫБРАТЬ
    Выбытие.Ссылка КАК Ссылка,
    Выбытие.Дата КАК Дата,
    Выбытие.Номер КАК Номер,
    // Получаем константы через параметры для оптимизации
    &Организация КАК Организация,
    &ДолжностьРуководителя КАК ДолжностьРуководителя,
    
    // Данные табличной части
    ВыбытиеСписокТМЦ.Номенклатура КАК Номенклатура,
    ВыбытиеСписокТМЦ.Количество КАК Количество,
    ВыбытиеСписокТМЦ.НомерСтроки КАК НомерСтроки,
    
    // Данные из регистра (используем ЕСТЬNULL для обработки отсутствующих записей)
    ЕСТЬNULL(ДанныеПоТМЦ.СсылкаНаСправочникНоменклатураБухгалтерии, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК НоменклатураБух,
    
    // Пример форматирования ответственных лиц сразу в запросе
    ВЫРАЗИТЬ(Выбытие.ПервыйОтветственный.Наименование КАК СТРОКА(100)) + " (" + 
    ВЫРАЗИТЬ(Выбытие.ПервыйОтветственный.Должность КАК СТРОКА(100)) + ")" КАК ОтветственныйФИО
ИЗ
    Документ.Выбытие КАК Выбытие
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.Выбытие.СписокТМЦ КАК ВыбытиеСписокТМЦ
        ПО Выбытие.Ссылка = ВыбытиеСписокТМЦ.Ссылка
        
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПоТМЦ КАК ДанныеПоТМЦ
        ПО ВыбытиеСписокТМЦ.Номенклатура = ДанныеПоТМЦ.СсылкаСпр
ГДЕ
    Выбытие.Ссылка = &Ссылка
ИТОГИ ПО
    Ссылка

Нюансы работы с периодическими регистрами

Если ваш регистр ДанныеПоТМЦ является периодическим (т.е. данные в нем меняются со временем), простое соединение с физической таблицей регистра может привести к дублированию строк в печатной форме, если для одной номенклатуры есть несколько записей в истории.

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


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеПоТМЦ.СрезПоследних(&ДатаДокумента, ) КАК ДанныеПоТМЦ
ПО ВыбытиеСписокТМЦ.Номенклатура = ДанныеПоТМЦ.СсылкаСпр

Здесь параметр &ДатаДокумента позволяет получить состояние данных именно на момент создания или проведения документа.

Обработка результата и вывод в табличный документ

После выполнения запроса важно правильно обойти его результаты. Поскольку мы использовали ИТОГИ ПО Ссылка, мы можем применить обход по группировкам. Проанализируем пример кода для модуля печати:


РезультатЗапроса = Запрос.Выполнить();

// Выборка по верхнему уровню (шапка документа)
ВыборкаШапка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаШапка.Следующий() Цикл
    
    // Заполняем область заголовка
    ОбластьЗаголовок.Параметры.Заполнить(ВыборкаШапка);
    ТабДок.Вывести(ОбластьЗаголовок);
    
    // Выводим шапку таблицы
    ТабДок.Вывести(ОбластьСписокТМЦШапка);
    
    // Выборка по детальным записям (строки ТЧ)
    ВыборкаСтроки = ВыборкаШапка.Выбрать();
    
    Пока ВыборкаСтроки.Следующий() Цикл
        
        // Логика выбора наименования номенклатуры (если из регистра пусто — берем из ТЧ)
        Если ЗначениеЗаполнено(ВыборкаСтроки.НоменклатураБух) Тогда
            НаименованиеДляПечати = ВыборкаСтроки.НоменклатураБух.Наименование;
        Иначе
            НаименованиеДляПечати = ВыборкаСтроки.Номенклатура.Наименование;
        КонецЕсли;
        
        ОбластьСписокТМЦ.Параметры.Заполнить(ВыборкаСтроки);
        ОбластьСписокТМЦ.Параметры.Номенклатура = НаименованиеДляПечати;
        
        ТабДок.Вывести(ОбластьСписокТМЦ);
        
    КонецЦикла;
    
КонецЦикла;

Важные практические советы

  1. Использование функции ЕСТЬNULL: Всегда оборачивайте поля из присоединяемых таблиц в ЕСТЬNULL. Это предотвратит появление пустых значений и ошибок типов при выводе в ТабличныйДокумент.
  2. Константы в параметрах: Не выбирайте константы (Организация, Руководитель) непосредственно в соединении запроса, как это показано в сообщении №2. Это создает лишнюю нагрузку на СУБД. Получите их заранее через Константы.Имя.Получить() и передайте в Запрос.УстановитьПараметр().
  3. Обращение через «точку»: Если данные, которые нужно добавить в колонку, являются реквизитом самой номенклатуры (например, Артикул), соединение с регистром не требуется. Можно использовать обращение ВыбытиеСписокТМЦ.Номенклатура.Артикул. Однако помните, что при большом количестве строк явное соединение с таблицей работает быстрее.
  4. Проверка на пустые ссылки: В коде печати всегда проверяйте результат на ПустаяСсылка(), чтобы корректно подставлять альтернативные значения (например, основное наименование номенклатуры, если бухгалтерское не задано).

Таким образом, мы рассмотрели полный цикл добавления колонки в результат запроса: от выбора правильного типа соединения до программного вывода в печатную форму. Использование левых соединений и итогов по ссылке документа является наиболее производительным и надежным способом решения этой задачи в системе 1С:Предприятие.

← На главную