При разработке отчетов и обработок в платформе 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией, когда синтаксически корректный запрос к регистру остатков отрабатывает без ошибок, но результирующая выборка оказывается абсолютно пустой. Проанализируем, почему это происходит, как устроен механизм запросов «семерки» и какие существуют альтернативные способы получения остатков и движений.
Посмотрим на типичный ошибочный запрос, в котором объявлены переменные регистра и группировка, но не указаны функции:
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Количество = Регистр.ПартииНаличие.Количество;
|СуммаРуб = Регистр.ПартииНаличие.СуммаРуб;
|Группировка Номенклатура;
|"//}}ЗАПРОС
;
Выясним причину такого поведения. Встроенный язык запросов 1С 7.7 кардинально отличается от классического SQL. Он ориентирован исключительно на агрегацию информации. Если в тексте запроса присутствуют секции переменных и группировок, но отсутствует хотя бы одна секция Функция, движок запросов платформы не формирует структуру результирующей таблицы для обхода. В результате метод Запрос.Выполнить() возвращает 1, однако обход по группировкам не находит ни одной строки.
Разберем, как правильно скорректировать запрос в зависимости от решаемой задачи.
Вариант А. Получение остатков по ресурсам
Если нам необходимо получить остатки номенклатуры на точку актуальности или выбранную дату, используем функцию КонОст() для числовых ресурсов:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с ВыбНачПериода по ВыбКонПериода;
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Количество = Регистр.ПартииНаличие.Количество;
|СуммаРуб = Регистр.ПартииНаличие.СуммаРуб;
|Функция ОстКол = КонОст(Количество);
|Функция ОстСумма = КонОст(СуммаРуб);
|Группировка Номенклатура без групп;
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Пока Запрос.Группировка("Номенклатура") = 1 Цикл
Сообщить(Строка(Запрос.Номенклатура) + " | Остаток: " + Запрос.ОстКол + " | Сумма: " + Запрос.ОстСумма);
КонецЦикла;
КонецЕсли;
Вариант Б. Простой подсчет записей или перебор без суммирования
Если получение конкретных суммовых итогов не требуется, а нужно лишь инициализировать построение дерева группировок, добавим служебную функцию Счётчик():
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Функция Счетчик = Счётчик();
|Группировка Номенклатура;
|"//}}ЗАПРОС
;
Вариант В. Получение детальных движений регистра
Если требуется получить плоский список документов движения, необходимо добавить группировку по регистратору и отключить расчет промежуточных итогов с помощью директивы Без Итогов;:
ТекстЗапроса =
"//{{ЗАПРОС(Сформировать)
|Период с ВыбНачПериода по ВыбКонПериода;
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Док = Регистр.ПартииНаличие.ТекущийДокумент;
|Количество = Регистр.ПартииНаличие.Количество;
|Функция ПриходКол = Приход(Количество);
|Функция РасходКол = Расход(Количество);
|Группировка Док;
|Без Итогов;
|"//}}ЗАПРОС
;
Если стоит задача быстро перебрать все записи или выгрузить актуальные остатки, в 1С 7.7 эффективнее использовать объектную модель регистра, которая работает значительно быстрее текстовых запросов.
Используем метод ВыгрузитьИтоги(). Это самый быстрый способ получить полный срез регистра в память.
Рег = СоздатьОбъект("Регистр.ПартииНаличие");
ТЗ = СоздатьОбъект("ТаблицаЗначений");
// Выгрузка итогов на точку актуальности
Рег.ВыгрузитьИтоги(ТЗ, 1, 1);
ТЗ.ВыбратьСтроку();
ВыбратьИтоги():
Позволяет перебрать рассчитанные остатки напрямую из таблицы итогов:
Рег = СоздатьОбъект("Регистр.ПартииНаличие");
Рег.ВыбратьИтоги();
Пока Рег.ПолучитьИтог() = 1 Цикл
Сообщить("Товар: " + Рег.Номенклатура + ", Остаток: " + Рег.Количество);
КонецЦикла;
Для детального анализа записей регистратора применим метод ВыбратьДвижения():
Рег = СоздатьОбъект("Регистр.ПартииНаличие");
Рег.ВыбратьДвижения(ВыбНачПериода, ВыбКонПериода);
Пока Рег.ПолучитьДвижение() = 1 Цикл
Сообщить("Документ: " + Рег.ТекущийДокумент + " | Товар: " + Рег.Номенклатура + " | Кол-во: " + Рег.Количество);
КонецЦикла;
Таким образом, для получения данных через объект Запрос всегда объявляйте функции агрегации (КонОст(), Приход(), Расход(), Сумма() или Счётчик()), а для простой выгрузки записей без условий агрегации используйте прямые методы объекта Регистр.