Как перебрать табличные части всех документов Оприходование товаров в 1С

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ исходной проблемы

Рассмотрим ситуацию, когда необходимо перебрать табличную часть Товары всех документов ОприходованиеТоваров. Проанализируем исходный код, который часто приводит к неудаче:


Процедура ЗаменитьЦеныНажатие(Элемент)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
                   |    Количество,
                   |    Сумма,
                   |    СуммаРегл,
                   |    Цена
                   |ИЗ
                   |    Документ.ОприходованиеТоваров.Товары КАК Товары
                   |ГДЕ
                   |    Ссылка = &Ссылка";
    Запрос.УстановитьПараметр("Ссылка", ДокСсылка);    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаСсылка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
КонецПроцедуры

В данном коде мы видим сразу несколько критических моментов, которые мешают достижению цели:

  1. Противоречие в условиях: В заголовке задачи указано «все документы», а в тексте запроса стоит фильтр ГДЕ Ссылка = &Ссылка. Это означает, что запрос вернет строки только одного выбранного документа.
  2. Отсутствие цикла обхода: Метод Выбрать() лишь подготавливает выборку, но не перебирает ее.
  3. Некорректный тип обхода: Использование ОбходРезультатаЗапроса.ПоГруппировкам при отсутствии итогов или группировок в самом запросе лишает смысла последующую итерацию.

Шаг 1: Правильное построение запроса для всех документов

Выясним причину, по которой данные не выбираются в нужном объеме. Если нам нужны строки табличных частей всех документов данного типа, мы должны полностью исключить условие по конкретной ссылке. Также крайне важно добавить в выборку саму ссылку на документ, чтобы понимать, к какому объекту относится конкретная строка.

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Товары.Ссылка КАК СсылкаНаДокумент,
    |   Товары.Номенклатура,
    |   Товары.Количество,
    |   Товары.Цена,
    |   Товары.Сумма
    |ИЗ
    |   Документ.ОприходованиеТоваров.Товары КАК Товары
    |ГДЕ
    |   Товары.Ссылка.Проведен = ИСТИНА"; // Добавим фильтр только по проведенным

В этом примере мы обращаемся к виртуальной таблице табличной части Товары. Система автоматически свяжет строки с документами-владельцами. Обратите внимание на использование алиаса Товары.Ссылка — это позволит нам в дальнейшем получить объект документа для редактирования.

Шаг 2: Реализация цикла обхода выборки

После выполнения запроса необходимо организовать перебор строк. Посмотрим на пример кода, который позволит нам «увидеть» данные:


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

Пока Выборка.Следующий() Цикл
    // Здесь мы получаем доступ к полям каждой строки
    Сообщить("Документ: " + Выборка.СсылкаНаДокумент + " Товар: " + Выборка.Номенклатура);
    // Выполняем нужные действия с Выборка.Цена, Выборка.Количество и т.д.
КонецЦикла;

Именно конструкция Пока Выборка.Следующий() Цикл обеспечивает последовательное чтение каждой записи из результата запроса. Без этого цикла код просто завершит работу сразу после получения РезультатЗапроса.

Шаг 3: Модификация данных (Изменение цен)

Если задача заключается не просто в чтении, а в изменении данных (как предполагает название процедуры ЗаменитьЦеныНажатие), нам нужно помнить: запрос предназначен только для чтения. Мы не можем присвоить новое значение полю Выборка.Цена и ожидать, что оно сохранится в базе данных.

Проанализируем алгоритм изменения данных:

  1. Получаем ссылку на документ из выборки.
  2. Создаем объект документа через ПолучитьОбъект().
  3. Находим нужную строку в табличной части объекта или перезаполняем всю ТЧ.
  4. Записываем объект.

Однако, перебор всех строк всех ТЧ и получение объекта на каждой итерации — это очень медленно. Правильнее будет сначала сгруппировать ссылки на документы, а затем обрабатывать каждый документ целиком. Посмотрим на оптимизированный пример:


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

ВыборкаДокументов = Запрос.Выполнить().Выбрать();

Пока ВыборкаДокументов.Следующий() Цикл
    ДокОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
    
    // Перебираем табличную часть уже внутри объекта
    Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл
        СтрокаТЧ.Цена = СтрокаТЧ.Цена * 1.1; // Увеличим цену на 10%
        // Не забываем пересчитать сумму, если это необходимо
        СтрокаТЧ.Сумма = СтрокаТЧ.Цена * СтрокаТЧ.Количество;
    КонецЦикла;
    
    Попытка
        ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        Сообщить("Не удалось записать документ " + ДокОбъект + ": " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Важные замечания по производительности и безопасности

При работе с массовым перебором всех документов в базе следует учитывать несколько факторов:

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

← На главную