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

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

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

Разбор исходной ситуации

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

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

Шаг 1: Подготовка процедуры на клиенте и сервере

Для начала создадим обработчик команды. Поскольку работа с базой данных (запросы) возможна только на стороне сервера, нам необходимо разделить логику на две части: клиентскую и серверную. Рассмотрим код вызова:


&НаКлиенте
Процедура ЗаполнитьИзОсновнойГруппы(Команда)
    // Вызываем серверную процедуру для выполнения запроса
    ПоискИЗаполнениеСтудентовНаСервере();
КонецПроцедуры

На сервере мы будем использовать объект Запрос. Это наиболее эффективный способ получения данных из табличных частей других объектов.

Шаг 2: Написание эффективного запроса

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

Рассмотрим правильную структуру текста запроса:


&НаСервере
Процедура ПоискИЗаполнениеСтудентовНаСервере()
    
    // Проверим, заполнена ли основная группа, чтобы избежать пустого запроса
    Если Объект.ОсновнаяГруппа.Пустая() Тогда
        Сообщить("Сначала выберите основную группу!");
        Возврат;
    КонецЕсли;

    Запрос = Новый Запрос;
    // Обращаемся к табличной части Студенты справочника Группы
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ГруппыСтуденты.ФИО КАК ФИО
        |ИЗ
        |   Справочник.Группы.Студенты КАК ГруппыСтуденты
        |ГДЕ
        |   ГруппыСтуденты.Ссылка = &СсылкаНаГруппу
        |УПОРЯДОЧИТЬ ПО
        |   ФИО";

    // Устанавливаем параметр. Важно: тип параметра должен совпадать с типом поля Ссылка
    Запрос.УстановитьПараметр("СсылкаНаГруппу", Объект.ОсновнаяГруппа);

    РезультатЗапроса = Запрос.Выполнить();
    
    // Выгружаем результат в таблицу значений
    ТаблицаРезультата = РезультатЗапроса.Выгрузить();
    
    // Загружаем данные в табличную часть текущего объекта
    Объект.Студенты.Загрузить(ТаблицаРезультата);

КонецПроцедуры

Шаг 3: Особенности использования метода Загрузить()

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

  1. Очистка данных: Метод Загрузить() полностью удаляет все старые строки из табличной части перед добавлением новых. Если вам нужно добавить данные к уже существующим, этот метод не подойдет — используйте цикл или метод ЗаполнитьЗначенияСвойств().
  2. Имена колонок: Обратите внимание на конструкцию ФИО КАК ФИО в тексте запроса. Псевдоним (то, что идет после слова КАК) должен в точности совпадать с именем реквизита в табличной части вашего справочника Подгруппы. Если в таблице реквизит называется СтудентНаименование, то и в запросе должно быть ГруппыСтуденты.ФИО КАК СтудентНаименование.
  3. Типы данных: Типы колонок в результате запроса должны соответствовать типам реквизитов ТЧ. Если в одной таблице это строка, а в другой — ссылка на справочник ФизическиеЛица, простая загрузка может привести к некорректным данным.

Вариант 2: Если отбор все же нужен по наименованию

Иногда возникают ситуации (например, при интеграции с внешними системами), когда у нас есть только текстовое название группы. В этом случае код запроса изменится. Посмотрим на пример реализации отбора по строке:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   ГруппыСтуденты.ФИО КАК ФИО
    |ИЗ
    |   Справочник.Группы.Студенты КАК ГруппыСтуденты
    |ГДЕ
    |   ГруппыСтуденты.Ссылка.Наименование = &НаименованиеГруппы";

Запрос.УстановитьПараметр("НаименованиеГруппы", "Группа №101");

Важно: Поиск по наименованию работает медленнее, чем по ссылке, так как СУБД приходится сравнивать текстовые строки. Используйте этот метод только в крайнем случае.

Дополнительные рекомендации для надежного кода

Рассмотрим еще несколько приемов, которые сделают ваше решение профессиональным:

1. Использование «Выбрать Различные». Если в исходной таблице могут быть дубли (например, по ошибке один и тот же студент внесен дважды), добавьте ключевое слово РАЗЛИЧНЫЕ сразу после ВЫБРАТЬ. Это гарантирует уникальность строк в новой таблице.

2. Проверка на пустоту результата. Перед загрузкой полезно проверить, нашел ли запрос хоть что-нибудь. Это позволит вывести пользователю предупреждение:


Если ТаблицаРезультата.Количество() = 0 Тогда
    Сообщить("В выбранной группе нет студентов!");
Иначе
    Объект.Студенты.Загрузить(ТаблицаРезультата);
КонецЕсли;

3. Ручное заполнение в цикле. Если вам нужно не просто скопировать данные, а выполнить какую-то логику (например, проверить, не находится ли студент в академическом отпуске), используйте обход выборки:


Выборка = РезультатЗапроса.Выбрать();
Объект.Студенты.Очистить(); // Очищаем вручную, если нужно
Пока Выборка.Следующая() Цикл
    НоваяСтрока = Объект.Студенты.Добавить();
    НоваяСтрока.ФИО = Выборка.ФИО;
    // Здесь можно добавить дополнительные проверки
КонецЦикла;

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

← На главную