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