Почему отборы на форме отчета в 1С 7.7 не влияют на результат выборки и как это исправить?

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

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

Анализ причин некорректной работы отборов

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

  1. Игнорирование значений реквизитов формы в коде: На форме могут присутствовать поля выбора (например, Район), но внутри процедур модуля выборка элементов справочника выполняется сплошным обходом через метод ВыбратьЭлементы(). В результате фильтрация по выбранным реквизитам просто не происходит.
  2. Параметр устанавливается, но не прописан в тексте SQL-запроса: При работе с прямыми запросами (например, через компонент ODBCRecordset) разработчики часто вызывают метод УстановитьТекстовыйПараметр(), но забывают добавить соответствующую метку (например, :ОстМеньше) в секцию WHERE текста запроса. В итоге параметр передается «вникуда».
  3. Выполнение SQL-запроса внутри циклов: Запуск прямых запросов к базе данных внутри встроенных циклов обхода справочников приводит к множественным обращениям к СУБД, сводя на нет преимущество прямого доступа и приводя к зацикливанию запросов по каждому элементу подряд.
  4. Отсутствие указаний по блокировкам: При выполнении прямых SQL-запросов к таблицам базы данных без хинта (nolock) создаются лишние блокировки таблиц на время формирования отчета.

Разбор ошибки на конкретном примере

Посмотрим на пример кода модуля формирования отчета, где допущены описанные выше ошибки:


СпрРайон = СоздатьОбъект("Справочник.Области");
СпрРайон.ПорядокКодов();
СпрРайон.ВыбратьЭлементы();
Пока СпрРайон.ПолучитьЭлемент() = 1 Цикл
    // Выводится секция для ВСЕХ районов подряд, игнорируя отбор на форме
    Таб.ВывестиСекцию("Район");
    
    СпрЗаказчик = СоздатьОбъект("Справочник.Заказчик");
    СпрЗаказчик.ВыбратьЭлементы();
    Пока СпрЗаказчик.ПолучитьЭлемент() = 1 Цикл
        Если СпрЗаказчик.Район = СпрРайон.ТекущийЭлемент() Тогда 
            
            RS.УстановитьТекстовыйПараметр("НачДата", НачПер);
            RS.УстановитьТекстовыйПараметр("КонДата", ОконПер);
            RS.УстановитьТекстовыйПараметр("ОстМеньше", ОстМеньше); // Параметр установлен, но в WHERE его нет!
            
            RS.УстановитьТекстовыйПараметр("ТекЗаказчик", СпрЗаказчик.ТекущийЭлемент());
            ТЗ = RS.ВыполнитьИнструкцию(ТекстЗапроса); // Запрос выполняется в цикле для каждого заказчика!
            ...
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

В приведенном коде реквизит формы Район вообще не задействован. Вся база районов и заказчиков обходится во вложенных циклах, а значение ОстМеньше передается в ODBCRecordset, но в тексте запроса секция WHERE фильтрацию по нему не содержит.

Рекомендации по исправлению и оптимизации кода

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

  1. Исключите выполнение запроса из циклов: Выполняйте ровно один SQL-запрос, который возвращает сразу все необходимые данные за выбранный период. По группировкам и иерархиям данные следует распределять уже после выгрузки в ТаблицуЗначений.
  2. Учитывайте заполнение реквизитов формы при формировании условий: Проверяйте, выбран ли элемент на форме (например, через Выбран() = 1 или ПустоеЗначение() = 0). В зависимости от этого динамически добавляйте условия в секцию WHERE SQL-запроса.
  3. Убедитесь, что все параметры объявлены в тексте SQL: Каждый вызов RS.УстановитьТекстовыйПараметр("ИмяПараметра", Значение) должен соотноситься с псевдонимом :ИмяПараметра в тексте SQL-запроса.
  4. Используйте подсказку чтения без блокировок: Добавляйте (nolock) к таблицам в секциях FROM и JOIN для предотвращения блокировок таблиц базы данных.

Пример правильного оформления секции источников данных в SQL-запросе с использованием (nolock):


|FROM
|   _1SJourn as Жур (nolock)
|INNER JOIN
|   $Документ.АктОбъемаРабот as Док (nolock) ON Док.IDDoc = Жур.IDDoc
|INNER JOIN
|   $Справочник.Объект as Спр (nolock) ON Спр.ID = $Док.Объект

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

← На главную