При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью получить данные не из самого документа, а из документов, на которые он ссылается в своей табличной части. Одной из типичных задач является проверка статуса этих подчиненных документов для вывода предупреждений пользователю. В этой статье мы подробно разберем, как правильно составить запрос, как обработать результаты и почему может возникать ошибка "Переменная не определена" при попытке обратиться к данным.
Рассмотрим ситуацию, когда у нас есть документ ЗаданиеПродавца, в табличной части которого хранятся ссылки на другие документы (например, ЗаказПоставщику). Нам нужно получить список этих заказов и проверить их статус. Если статус документа является "Новым", мы должны предупредить пользователя.
Первым шагом проанализируем структуру запроса. Чтобы получить статус связанного документа, мы используем механизм разыменования ссылочных полей (обращение "через точку"). Рассмотрим пример правильного запроса:
ВЫБРАТЬ
ЗаданиеПродавцаДокументы.Документ КАК Док,
ЗаданиеПродавцаДокументы.Документ.Номер КАК Номер,
ЗаданиеПродавцаДокументы.Документ.Контрагент КАК Контрагент,
ЗаданиеПродавцаДокументы.Документ.Статус КАК Статус
ИЗ
Документ.ЗаданиеПродавца.Документы КАК ЗаданиеПродавцаДокументы
ГДЕ
ЗаданиеПродавцаДокументы.Ссылка = &ЗаданиеПродавца
Важно помнить, что каждое такое обращение ("через точку") в языке запросов 1С преобразуется в левое соединение (LEFT JOIN) на уровне СУБД. Это удобно, но при работе с очень большими объемами данных следует об этом помнить в целях оптимизации.
Часто разработчики выполняют запрос, выгружают его в таблицу значений на форме, но при попытке обратиться к полю в цикле Для каждого Строка Из ТаблицаДоков Цикл получают ошибку Переменная не определена (Статус) или поле просто оказывается пустым. Выясним причину этой ситуации.
Проанализируем метод Загрузить(). Когда мы пишем ТаблицаДоков.Загрузить(РезультатЗапроса.Выгрузить()), система сопоставляет колонки из результата запроса с колонками, которые уже созданы в объекте ТаблицаЗначений. Если на форме в реквизите ТаблицаДоков вы создали колонки "Док", "Номер" и "Контрагент", но забыли добавить колонку "Статус", то при загрузке данных система просто проигнорирует поле "Статус" из запроса. Данные не будут записаны в таблицу на форме, и вы не сможете к ним обратиться в цикле.
Решение: Обязательно проверьте состав колонок вашей таблицы значений на форме (в закладке "Реквизиты"). Имя колонки должно в точности совпадать с псевдонимом (КАК Статус) из запроса.
Статус документа в 1С обычно имеет тип ПеречислениеСсылка. Для сравнения статуса в программном коде и в самом запросе используются разные подходы. Разберем их по шагам.
Вариант 1: Проверка в цикле (после выполнения запроса)
Если нам нужно вывести предупреждение пользователю только для определенных строк, мы обходим таблицу в цикле:
Для каждого Строка Из ТаблицаДоков Цикл
Если Строка.Статус = Перечисления.СтатусыЗаказов.Новый Тогда
// Здесь мы можем собрать информацию для предупреждения
Сообщить("Документ № " + Строка.Номер + " имеет статус Новый!");
КонецЕсли;
КонецЦикла;
Вариант 2: Фильтрация в самом запросе
Если нам вообще не нужны документы с определенным статусом, эффективнее отсечь их еще на уровне базы данных. В запросах для этого используется функция ЗНАЧЕНИЕ():
ГДЕ
ЗаданиеПродавцаДокументы.Документ.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Новый)
Рассмотрим два способа обработки данных запроса, которые помогут избежать ошибок обращения к данным.
Способ 1: Использование выборки (без выгрузки в таблицу)
Если вам не нужно отображать данные на форме, а нужно просто их проанализировать, используйте объект ВыборкаИзРезультатаЗапроса. Это работает быстрее и потребляет меньше памяти.
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Статус <> Перечисления.СтатусыЗаказов.Новый Тогда
// Обработка данных
КонецЕсли;
КонецЦикла;
Способ 2: Выгрузка в промежуточную таблицу
Если вы хотите сначала обработать данные, а потом уже загрузить их в таблицу на форме, можно создать таблицу значений в памяти программно:
ТЗ = Запрос.Выполнить().Выгрузить();
// Теперь у ТЗ есть все колонки, которые были в запросе,
// даже если их нет на форме.
Для каждого Стр Из ТЗ Цикл
Если Стр.Статус = Перечисления.СтатусыЗаказов.Новый Тогда
// Логика обработки
КонецЕсли;
КонецЦикла;
Проанализируем контекст исполнения кода. В управляемых формах 1С запрос всегда выполняется на сервере. Однако методы вывода сообщений пользователю, такие как ПоказатьПредупреждение(), работают только на клиенте.
Посмотрим на правильную архитектуру решения задачи:
ПоказатьПредупреждение().Это позволит избежать ошибок при выполнении кода и обеспечит корректную работу интерфейса программы. Помните: правильное определение колонок в ТаблицаЗначений и корректное использование обращений к Перечисления — залог стабильной работы вашего кода в 1С.