Как правильно выполнить запрос и выгрузить результат в таблицу значений в 1С 7.7 без лишних строк

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

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

Причина появления пустых строк при выгрузке запроса

Рассмотрим стандартную ситуацию: вы создаете объект Запрос, описываете текст запроса с группировками и условиями, выполняете его и используете метод Выгрузить(). Однако при обходе полученной таблицы значений вы замечаете, что первая строка (или несколько строк) оказывается пустой. Проанализируем, почему это происходит.

В 1С 7.7 объект Запрос по своей архитектуре всегда ориентирован на построение иерархических отчетов с итогами. Когда мы вызываем метод Выгрузить(ТЗ) с параметрами по умолчанию, платформа автоматически включает в таблицу строки итогов по группировкам. Самая первая строка в такой таблице — это «Общий итог» по всей выборке. Если в вашем запросе не используются агрегатные функции (такие как Сумма, Среднее или Количество), эта строка будет содержать пустые значения в колонках данных, что и сбивает с толку.

Выясним, как управлять этим поведением. Обратимся к синтаксису метода Выгрузить():

Выгрузить(ТаблЗнач, Флаг, Итоги)

Ключевым здесь является третий параметр — Итоги. Рассмотрим его значения:

  1. 0 — итоги по группировкам не выводить (именно это значение позволяет получить «чистые» данные);
  2. 1 — итоги по группировкам выводить сверху (значение по умолчанию);
  3. 2 — итоги по группировкам выводить снизу;
  4. 3 — итоги по группировкам выводить и сверху, и снизу.

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


ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|ФизЛица = Справочник.ФизЛица.ТекущийЭлемент;
|ПолнНаименование = Справочник.ФизЛица.ПолнНаименование;
|Группировка ФизЛица без упорядочивания без групп;
|Условие(ПолнНаименование = ФИО);";

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

Оптимизация поиска: почему запрос может работать медленно

Многие разработчики отмечают, что обычный перебор справочника методом ВыбратьЭлементы() иногда работает быстрее, чем объект Запрос. Разберем ситуацию, когда это действительно так. В 1С 7.7 критически важно, используются ли в блоке Условие() функции языка (например, СОКРЛП, Врег и др.).

Если вы пишете Условие(СОКРЛП(ПолнНаименование) = ФИО), платформа не может использовать индексы базы данных. Она вынуждена прочитать каждую запись из файла (или таблицы SQL), передать её в программный стек, выполнить функцию обрезания пробелов и только потом сравнить. Это превращает запрос в классический «скан» всей таблицы, что на больших объемах данных (десятки тысяч записей) занимает значительное время.

Рекомендация: старайтесь подготавливать значение поиска (переменную ФИО) заранее, а в условии использовать чистое сравнение реквизитов без функций. Если же реквизит не индексирован (свойство «Сортировка» выключено), запрос всё равно будет медленным.

Поиск однофамильцев через таблицу значений в памяти

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

Проанализируем алгоритм:

  1. Одним запросом выбираем все необходимые данные из справочника (например, идентификатор и ФИО).
  2. Выгружаем их в ТаблицуЗначений.
  3. Если мы ищем дубли внутри самой базы, используем метод Свернуть().

Пример кода для поиска дублей в справочнике:


ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("ФизЛицо");
ТЗ.НоваяКолонка("ФИО");
ТЗ.НоваяКолонка("Количество");

Спр = СоздатьОбъект("Справочник.ФизЛица");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    ТЗ.НоваяСтрока();
    ТЗ.ФизЛицо = Спр.ТекущийЭлемент();
    ТЗ.ФИО = Спр.Наименование;
    ТЗ.Количество = 1;
КонецЦикла;

// Сворачиваем таблицу по ФИО, суммируя колонку Количество
ТЗ.Свернуть("ФИО", "Количество");

// Теперь в ТЗ остались только уникальные имена с указанием их частоты
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Если ТЗ.Количество > 1 Тогда
        Сообщить("Обнаружен дубль или однофамилец: " + ТЗ.ФИО + " (встречается " + ТЗ.Количество + " раз)");
    КонецЦикла;
КонецЦикла;

Нюансы работы с реквизитом ПолнНаименование

В типовых конфигурациях 1С 7.7 реквизит ПолнНаименование часто имеет неограниченную длину. Важно помнить, что для строк неограниченной длины невозможно установить свойство «Сортировка» в конфигураторе. Это означает, что платформа физически не может создать индекс по этому полю.

Если вам требуется мгновенный поиск по полному имени, рассмотрим два пути решения этой проблемы:

  1. Ограничение длины: изменить тип реквизита на «Строка» фиксированной длины (например, 150-240 символов) и включить «Сортировку». После этого станет доступен метод НайтиПоРеквизиту(), который работает практически мгновенно.
  2. Использование стандартного Наименования: часто полное наименование дублирует краткое в первых 100 символах. Поиск по индексированному полю Наименование с последующей программной проверкой полного соответствия будет в разы быстрее, чем поиск по неиндексированному длинному полю.

Использование метода НайтиПоРеквизиту

Если вы все же включили индексацию («Сортировку») для нужного вам поля, вместо тяжелого объекта Запрос лучше использовать штатный метод поиска справочника. Рассмотрим, как правильно искать всех однофамильцев с его помощью:


Спр = СоздатьОбъект("Справочник.ФизЛица");
ФИОДляПоиска = "Иванов Иван Иванович";

// Метод НайтиПоРеквизиту находит только ПЕРВОЕ вхождение
Если Спр.НайтиПоРеквизиту("ПолнНаименование", ФИОДляПоиска, 1) = 1 Тогда
    // Чтобы найти остальных, нужно продолжать выборку в цикле
    // Но так как элементы с одинаковым значением реквизита при включенной сортировке
    // идут друг за другом, мы можем продолжить обход
    Пока Спр.ТекущийЭлемент().Selected() = 1 Цикл
        Если Спр.ПолнНаименование <> ФИОДляПоиска Тогда
             Прервать; // Больше совпадений нет
        КонецЕсли;
        
        Сообщить("Найден: " + Спр.ТекущийЭлемент());
        
        Если Спр.ПолучитьЭлемент() = 0 Тогда
            Прервать;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

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

← На главную