Как правильно оформить запрос по остаткам регистра и обходить группировки в 1С 7.7?

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

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

Основные ошибки при формировании запросов в 1С 7.7

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

  1. Использование только одного цикла обхода: Если в тексте запроса указано несколько операторов Группировка, стандартный метод Запрос.Группировка(1) обходит только верхний уровень иерархии (первую группировку). Все вложенные группировки при этом остаются незаполненными.
  2. Обращение к текстовым реквизитам через точку в запросе: Конструкции вида Регистр.Заявки.Фирма.Наименование или Регистр.Заявки.Номенклатура.Код заставляют систему группировать данные по строковым значениям, а не по ссылочным объектам справочников. Это приводит к разрыву связей и некорректной агрегации данных. Переменная запроса должна ссылаться на измерение напрямую (например, Регистр.Заявки.Фирма).
  3. Расчет остатков по показателям движения вместо ресурсов: Функция КонОст() предназначена исключительно для работы с ресурсами регистра остатков (например, Регистр.Заявки.Количество). Использование реквизитов движения (таких как КоличествоРасход) приводит к ошибкам расчета.

Способ 1. Использование вложенных циклов для обхода группировок

Если в запросе объявлено несколько уровней группировки, для их последовательной обработки требуется организовать вложенные циклы Пока Запрос.Группировка(N) = 1 Цикл, где N — номер группировки по порядку ее указания в тексте запроса.

Рассмотрим пример правильного кода запроса и его обхода:


Процедура Сформировать()
    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("Сформировать");
    
    Текст = "
    |Фирма = Регистр.Заявки.Фирма;
    |Контрагент = Регистр.Заявки.ДоговорПокупателя.Владелец;
    |Договор = Регистр.Заявки.ДоговорПокупателя;
    |Номенклатура = Регистр.Заявки.Номенклатура;
    |Количество = Регистр.Заявки.Количество;
    |Функция КонОст = КонОст(Количество);
    |Группировка Фирма без групп;
    |Группировка Контрагент без групп;
    |Группировка Договор без групп;
    |Группировка Номенклатура без групп;
    |";
    
    Запрос = СоздатьОбъект("Запрос");
    Если Запрос.Выполнить(Текст) = 1 Тогда
        Пока Запрос.Группировка(1) = 1 Цикл
            // Уровень 1: Фирма
            ФирмаЗапроса = Запрос.Фирма;
            
            Пока Запрос.Группировка(2) = 1 Цикл
                // Уровень 2: Контрагент
                КонтрагентЗапроса = Запрос.Контрагент;
                
                Пока Запрос.Группировка(3) = 1 Цикл
                    // Уровень 3: Договор
                    ДоговорЗапроса = Запрос.Договор;
                    
                    Пока Запрос.Группировка(4) = 1 Цикл
                        // Уровень 4: Детальная номенклатура и остаток
                        НоменклатураЗапроса = Запрос.Номенклатура;
                        КодНоменклатуры = Запрос.Номенклатура.Код;
                        ОстатокТовара = Запрос.КонОст;
                        
                        Таб.ВывестиСекцию("Строка");
                    КонецЦикла;
                КонецЦикла;
            КонецЦикла;
        КонецЦикла;
    КонецЕсли;
    
    Таб.Показать("Отчет по остаткам");
КонецПроцедуры

Способ 2. Линейный обход детальных записей без вложенности

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

Посмотрим на пример упрощенного цикла:


Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(Текст) = 1 Тогда
    // Обход всех детальных записей по всем группировкам подряд
    Пока Запрос.Группировка() = 1 Цикл
        Выражение_1 = Запрос.Фирма;
        Выражение_2 = Запрос.Контрагент;
        Выражение_3 = Запрос.Договор;
        Выражение_4 = Запрос.Номенклатура;
        Выражение_5 = Запрос.КонОст;
        
        Таб.ВывестиСекцию("Строка");
    КонецЦикла;
КонецЦикла;

Способ 3. Прямая выгрузка в Таблицу Значений

Для программной обработки результатов запроса удобно использовать штатный метод Запрос.Выгрузить(). Он формирует объект ТаблицаЗначений, в который помещаются все поля запроса и итоговые значения ресурсов.


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

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

Использование встроенного конструктора запросов

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

← На главную