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