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

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

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

Разбор ошибки метода Выбрать() и структуры отбора

Рассмотрим ситуацию, когда при попытке отбора документов возникает ошибка «Недопустимое значение параметра (параметр номер '3')». Эта ошибка обычно связана с тем, что в метод Выбрать() передается структура отбора, содержащая поля, по которым система не может выполнить индексированный поиск.

Проанализируем правила использования метода Выбрать() для менеджера документов:

  1. В качестве полей для отбора могут выступать только Дата и реквизиты документа, для которых в конфигураторе установлено свойство «Индексировать» или «Индексировать с дополнительным упорядочиванием».
  2. Стандартный реквизит Номер часто не поддерживается этим методом напрямую, если требуется сложный поиск.
  3. Ключи в структуре отбора должны строго соответствовать именам реквизитов документа в метаданных (с учетом регистра).

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

Выбор метода поиска: НайтиПоРеквизиту или Запрос?

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


ДокументСсылка = Документы.АрхивныйДокумент.НайтиПоРеквизиту("ДецНомер", ЗначениеПоиска);
Если Не ДокументСсылка.Пустая() Тогда
    // Работаем с документом
КонецЕсли;

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

Работа с табличными частями в запросах

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

Рассмотрим пример ошибочного кода:


ВЫБРАТЬ
    АрхивныйДокумент.Ссылка,
    АрхивныйДокумент.Проекты.(НомерСтроки, КодПроекта) КАК Проекты
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    Документ.АрхивныйДокумент КАК АрхивныйДокумент

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

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


ВЫБРАТЬ
    АрхивныйДокументПроекты.Ссылка КАК ДокументСсылка,
    АрхивныйДокументПроекты.КодПроекта КАК КодПроекта
ИЗ
    Документ.АрхивныйДокумент.Проекты КАК АрхивныйДокументПроекты
ГДЕ
    АрхивныйДокументПроекты.Ссылка В (&СписокДокументов)

Такой подход позволяет получить плоский список всех строк табличных частей для заданного списка документов. Это работает значительно быстрее, чем перебор документов в цикле и обращение к их объектным данным.

Оптимизация выполнения запросов

Разберем еще один важный момент — проверку результата запроса на пустоту. Посмотрим на неоптимальный код:


Если Запрос.Выполнить().Пустой() Тогда
    Сообщить("Данных нет");
Иначе
    Выборка = Запрос.Выполнить().Выбрать();
    // ...
КонецЕсли;

В данном примере метод Выполнить() вызывается дважды. Это означает, что сервер 1С дважды отправит запрос к СУБД, что увеличивает нагрузку на систему. Правильнее сохранить результат в переменную:


РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
    Сообщить("Данных нет");
Иначе
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        // Обработка данных
    КонецЦикла;
КонецЕсли;

Как вывести данные табличной части «через запятую»

Если задача стоит в том, чтобы вывести список проектов из табличной части в одну ячейку отчета (через запятую), мы можем использовать следующий алгоритм в коде 1С:

  1. Выполняем запрос к табличной части документа.
  2. Обходим результат запроса и собираем значения в массив.
  3. Используем функцию СтрСоединить() для формирования итоговой строки.

Рассмотрим программный пример реализации:


МассивПроектов = Новый Массив;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    МассивПроектов.Добавить(Строка(Выборка.КодПроекта));
КонецЦикла;

СтрокаДляОтчета = СтрСоединить(МассивПроектов, ", ");

Подведем итог: для эффективного отбора документов используйте Запрос с фильтрацией в секции ГДЕ. При необходимости получения данных из табличных частей обращайтесь к ним напрямую через точку в описании источника данных запроса (например, Документ.Имя.ТабличнаяЧасть). Это обеспечит высокую скорость работы программы и отсутствие ошибок, связанных с ограничениями временных таблиц и методов старого стиля типа Выбрать().

← На главную