При работе с языком запросов платформы 1С:Предприятие 7.7 разработчики часто сталкиваются с ситуацией, когда результат запроса сворачивается или выводит неполные данные по измерителям (организациям, контрагентам, номенклатуре). Разберем причины возникновения таких ошибок и рассмотрим, как правильно выгружать и обходить остатки регистров накопления.
Проанализируем типовой сценарий: необходимо получить остатки по незакрытым заявкам покупателей в разрезе нескольких измерений (организация, контрагент, договор и номенклатура). Выясним, почему запрос может возвращать пустые поля или некорректно сворачивать строки:
Группировка, стандартный метод Запрос.Группировка(1) обходит только верхний уровень иерархии (первую группировку). Все вложенные группировки при этом остаются незаполненными.Регистр.Заявки.Фирма.Наименование или Регистр.Заявки.Номенклатура.Код заставляют систему группировать данные по строковым значениям, а не по ссылочным объектам справочников. Это приводит к разрыву связей и некорректной агрегации данных. Переменная запроса должна ссылаться на измерение напрямую (например, Регистр.Заявки.Фирма).КонОст() предназначена исключительно для работы с ресурсами регистра остатков (например, Регистр.Заявки.Количество). Использование реквизитов движения (таких как КоличествоРасход) приводит к ошибкам расчета.Если в запросе объявлено несколько уровней группировки, для их последовательной обработки требуется организовать вложенные циклы Пока Запрос.Группировка(N) = 1 Цикл, где N — номер группировки по порядку ее указания в тексте запроса.
Рассмотрим пример правильного кода запроса и его обхода:
Процедура Сформировать()
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("Сформировать");
Текст = "
|Фирма = Регистр.Заявки.Фирма;
|Контрагент = Регистр.Заявки.ДоговорПокупателя.Владелец;
|Договор = Регистр.Заявки.ДоговорПокупателя;
|Номенклатура = Регистр.Заявки.Номенклатура;
|Количество = Регистр.Заявки.Количество;
|Функция КонОст = КонОст(Количество);
|Группировка Фирма без групп;
|Группировка Контрагент без групп;
|Группировка Договор без групп;
|Группировка Номенклатура без групп;
|";
Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(Текст) = 1 Тогда
Пока Запрос.Группировка(1) = 1 Цикл
// Уровень 1: Фирма
ФирмаЗапроса = Запрос.Фирма;
Пока Запрос.Группировка(2) = 1 Цикл
// Уровень 2: Контрагент
КонтрагентЗапроса = Запрос.Контрагент;
Пока Запрос.Группировка(3) = 1 Цикл
// Уровень 3: Договор
ДоговорЗапроса = Запрос.Договор;
Пока Запрос.Группировка(4) = 1 Цикл
// Уровень 4: Детальная номенклатура и остаток
НоменклатураЗапроса = Запрос.Номенклатура;
КодНоменклатуры = Запрос.Номенклатура.Код;
ОстатокТовара = Запрос.КонОст;
Таб.ВывестиСекцию("Строка");
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЕсли;
Таб.Показать("Отчет по остаткам");
КонецПроцедуры
Если промежуточные итоги по верхним группировкам не требуются, а нужно лишь вывести конечные строки с данными, можно использовать метод Запрос.Группировка() без передачи номера параметров. В этом случае платформа автоматически переберет только нижний детальный уровень выборки.
Посмотрим на пример упрощенного цикла:
Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(Текст) = 1 Тогда
// Обход всех детальных записей по всем группировкам подряд
Пока Запрос.Группировка() = 1 Цикл
Выражение_1 = Запрос.Фирма;
Выражение_2 = Запрос.Контрагент;
Выражение_3 = Запрос.Договор;
Выражение_4 = Запрос.Номенклатура;
Выражение_5 = Запрос.КонОст;
Таб.ВывестиСекцию("Строка");
КонецЦикла;
КонецЦикла;
Для программной обработки результатов запроса удобно использовать штатный метод Запрос.Выгрузить(). Он формирует объект ТаблицаЗначений, в который помещаются все поля запроса и итоговые значения ресурсов.
ТЗРезультат = СоздатьОбъект("ТаблицаЗначений");
Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(Текст) = 1 Тогда
// Выгружаем детальные данные запроса в таблицу значений
Запрос.Выгрузить(ТЗРезультат, 0, 0);
// Перебираем полученную таблицу
ТЗРезультат.ВыбратьСтроки();
Пока ТЗРезультат.ПолучитьСтроку() = 1 Цикл
Сообщить("Номенклатура: " + ТЗРезультат.Номенклатура + " | Остаток: " + ТЗРезультат.КонОст);
КонецЦикла;
КонецЕсли;
Для ускорения написания кода и исключения синтаксических ошибок в 1С 7.7 предусмотрен встроенный Конструктор запросов. Вызвать его можно в режиме Конфигуратора через контекстное меню или кнопку на панели инструментов при редактировании модуля. Конструктор автоматически расставляет корректные имена ресурсов, функций и директивы группировок.