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