Почему запрос по документу в 1С 7.7 не возвращает данные и не заходит в цикл?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке отчетов, обработок выгрузки или отладке правил конвертации данных на платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией: синтаксически запрос написан правильно, выполняется без ошибок, однако метод Запрос.Группировка(...) возвращает значение 0, и код не заходит в цикл обработки результатов.

Разберем детально, почему возникает такое поведение, какие особенности работы языка запросов 1С 7.7 к этому приводят и какими способами можно корректно получить данные по конкретному документу.

Анализ проблемы: поведение периода по умолчанию в запросах 1С 7.7

Посмотрим на исходный пример текста запроса, который не возвращает выборку:


ТекДок = СоздатьОбъект("Документ");
ТекДок.НайтиДокумент(СсылкаДок);

Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(Сформировать)
|ОбрабатыватьДокументы все;
|ПеремОбъект = Документ.УслугиСтороннихОрганизаций.ТекущийДокумент;
|Группировка ПеремОбъект;
|Условие(ПеремОбъект = ТекДок);
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Возврат;
КонецЕсли;

Пока Запрос.Группировка("ПеремОбъект") = 1 Цикл
    // В этот цикл выполнение не заходит
КонецЦикла;

Проанализируем две ключевые причины, из-за которых данный код не работает:

  1. Отсутствие секции периода. В платформе 1С 7.7, если в тексте запроса не указана строка Период с ... по ...;, платформа не выбирает данные за всю историю базы. По умолчанию интервал выборки для документов и регистров схлопывается до одной точки — Точки Актуальности (ТА) или Рабочей даты. Если искомый документ создан любой другой датой, запрос вернет пустой результат.
  2. Несоответствие типов при сравнении в условии. Объект, созданный через СоздатьОбъект("Документ"), является агрегатным типом контекста (итератором), а не самой ссылкой на конкретный документ в базе. Для сравнения в секции Условие(...) необходимо передавать конкретную ссылку — значение реквизита формы типа документ или метод ТекДок.ТекущийДокумент().

Решение 1. Явное указание периода и передача ссылки в условие

Чтобы запрос в 1С 7.7 нашел документ, обязательно добавим секцию периода и укажем корректную ссылку на объект:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = 
"//{{ЗАПРОС(Сформировать)
|Период с ДатаНачала по ДатаОкончания;
|ОбрабатыватьДокументы все;
|ПеремОбъект = Документ.УслугиСтороннихОрганизаций.ТекущийДокумент;
|Группировка ПеремОбъект Без Итогов;
|Условие(ПеремОбъект = СсылкаДок);
|"//}}ЗАПРОС
;

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка("ПеремОбъект") = 1 Цикл
        // Обработка найденного документа
    КонецЦикла;
КонецЕсли;

Обратим внимание на директиву Без Итогов после группировки. Если в запросе не вычисляются агрегатные функции (например, Сумма или Количество), директива отключает расчет служебных итогов, что ускоряет выборку и исключает пустые обходы дерева результата.

Решение 2. Оптимизация периода для поиска одного документа

Если в коде необходимо выполнить именно объект Запрос для проверки или извлечения данных одного известного документа, не стоит открывать широкий период за несколько лет. Запрос 1С 7.7 сканирует таблицы журнала за указанный интервал и создает временные файлы.

Рассмотрим, как сузить границы периода до точной даты документа:


ТекДок = СоздатьОбъект("Документ.УслугиСтороннихОрганизаций");
Если ТекДок.НайтиДокумент(СсылкаДок) = 1 Тогда
    ДатаДокумента = ТекДок.ДатаДок;
    СсылкаНаОбъект = ТекДок.ТекущийДокумент();

    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = 
    "Период с '" + ДатаДокумента + "' по '" + ДатаДокумента + "';
    |ОбрабатыватьДокументы Все;
    |ПеремОбъект = Документ.УслугиСтороннихОрганизаций.ТекущийДокумент;
    |Группировка ПеремОбъект Без Итогов;
    |Условие(ПеремОбъект = СсылкаНаОбъект);";

    Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
        Пока Запрос.Группировка(1) = 1 Цикл
            // Документ успешно найден в выборке
        КонецЦикла;
    КонецЕсли;
КонецЕсли;

Решение 3. Прямое позиционирование без использования объекта «Запрос»

Выясним, целесообразно ли вообще применять Запрос, если ссылка на документ уже известна. Механизм запросов в 1С 7.7 для одного объекта является избыточным. Для чтения реквизитов шапки и строк табличной части гораздо быстрее использовать штатные методы агрегатного объекта Документ:


Док = СоздатьОбъект("Документ.УслугиСтороннихОрганизаций");
Если Док.НайтиДокумент(СсылкаДок) = 1 Тогда
    // Документ позиционирован
    // Доступны реквизиты шапки: Док.НомерДок, Док.ДатаДок, Док.Контрагент и т.д.
    
    // Обход табличной части:
    Док.ВыбратьСтроки();
    Пока Док.ПолучитьСтроку() = 1 Цикл
        // Доступны реквизиты строк: Док.Услуга, Док.Сумма и т.д.
    КонецЦикла;
КонецЕсли;

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


Док = СоздатьОбъект("Документ.УслугиСтороннихОрганизаций");
Док.ВыбратьДокументы(ДатаНачала, ДатаОкончания);
Пока Док.ПолучитьДокумент() = 1 Цикл
    // Выборка документов за период выполняется напрямую через журнал
КонецЦикла;
← На главную