Как найти конкретный документ по реквизиту с помощью запроса в 1С 7.7

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

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

Проанализируем исходную попытку построения выборки:


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

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

  1. Некорректное условие отбора: выражение Условие(НомерНаСайте = НомерНаСайте) сравнивает внешнюю переменную саму с собой, потому что реквизит документа с таким именем внутри запроса вообще не был объявлен. Внутренняя переменная запроса обязательно должна быть связана с реквизитом через оператор присваивания.
  2. Отсутствие секции группировки: метод Запрос.Выгрузить() формирует колонки в таблице значений исключительно по переменным, для которых задано предложение Группировка, либо по агрегатным функциям (таким как Сумма или Количество). Переменные, описанные просто через присваивание (в нашем случае ТекущийДокумент), в колонки результирующей таблицы не попадают.
  3. Особенности строковых типов в базе данных: реквизиты строкового типа в метаданных 1С 7.7 имеют фиксированную длину и в базе дополняются пробелами справа. Простое сравнение без обрезки пробелов часто приводит к тому, что условие не выполняется даже при видимом совпадении строк.

Исправление запроса: объявление реквизитов и добавление группировки

Рассмотрим, как должен выглядеть рабочий запрос к документам конфигурации. Для того чтобы документ отобразился в результатах, мы должны:

  1. Описать переменную запроса, указывающую на реквизит шапки: зНомерНаСайте = Документ.ЗаказПокупателя.НомерНаСайте;.
  2. Использовать функцию СокрЛП() внутри условия или предварительно подготовить строку нужной длины.
  3. Добавить обязательное предложение Группировка по документу.

Посмотрим на исправленный вариант программного кода:


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

Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Предупреждение("Ошибка выполнения запроса!");
    Возврат;
КонецЕсли;

ТТ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТТ, 0, 0);

ТТ.ВыбратьСтроки();
Пока ТТ.ПолучитьСтроку() = 1 Цикл
    НайденныйДокумент = ТТ.ТекущийДокумент;
    Сообщить("Найден документ: " + НайденныйДокумент);
КонецЦикла;

Обратим внимание: выгружать весь результат в ТаблицаЗначений ради поиска одного объекта не обязательно. Гораздо эффективнее и экономнее по памяти выполнить прямой обход группировок запроса:


Пока Запрос.Группировка("ТекущийДокумент") = 1 Цикл
    НайденныйДокумент = Запрос.ТекущийДокумент;
    Сообщить("Найден документ: " + НайденныйДокумент);
    Прервать; // Завершаем цикл, если нужен только первый найденный документ
КонецЦикла;

Альтернативные способы поиска: перебор через объект «Документ»

В ходе обсуждений нередко звучит совет использовать метод НайтиПоРеквизиту(). Важно помнить: в платформе 1С 7.7 метод НайтиПоРеквизиту() существует только у объекта Справочник. У объекта Документ такого метода нет.

Если документов за период немного, можно обойтись стандартной выборкой по периоду с помощью метода ВыбратьДокументы(). По скорости работы в файловой базе (DBF) последовательный перебор документов одного вида практически не уступает запросу, так как внутренний механизм запроса 1С 7.7 в файловом режиме также последовательно считывает записи журнала.

Разберем пример реализации через объект Документ:


ИскомыйНомер = СокрЛП(НомерНаСайте);
мДок = СоздатьОбъект("Документ.ЗаказПокупателя");

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

Быстрый поиск через механизм отборов

Если поиск конкретного документа по стороннему номеру или идентификатору сайта требуется выполнять регулярно и быстро, последовательное сканирование журналов за целый год создаст сильную нагрузку на дисковую подсистему. В таких случаях применяют штатный механизм отбора:

  1. В конфигураторе для реквизита настраивается объект метаданных Графа отбора (либо включается признак «Отбор» у общего реквизита).
  2. Поиск выполняется через метод ВыбратьПоЗначению(). Обратите внимание: данный метод работает исключительно с нетипизированным объектом СоздатьОбъект("Документ"). Попытка вызвать его у объекта определенного вида (например, Документ.ЗаказПокупателя) приведет к ошибке выполнения программы.

Рассмотрим пример быстрого индексного отбора:


ИскомыйНомер = СокрЛП(НомерНаСайте);
ВыборкаДок = СоздатьОбъект("Документ");

// "НомерНаСайте" здесь - имя Графы отбора в конфигураторе
ВыборкаДок.ВыбратьПоЗначению(НачГода(ТекущаяДата()), КонГода(ТекущаяДата()), "НомерНаСайте", ИскомыйНомер);

Пока ВыборкаДок.ПолучитьДокумент() = 1 Цикл
    Если ВыборкаДок.Вид() = "ЗаказПокупателя" Тогда
        Сообщить("Найден целевой заказ: " + ВыборкаДок.ТекущийДокумент());
        Прервать;
    КонецЕсли;
КонецЦикла;

Таким образом, для поиска документа запросом в 1С 7.7 необходимо обязательно связывать реквизиты метаданных с внутренними переменными запроса, контролировать длину строковых реквизитов и всегда объявлять секцию Группировка для получения выходных полей в выборке.

← На главную