Почему запрос в 1С 7.7 показывает количество только первой партии и как это исправить?

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

При работе с запросами к регистрам в платформе 1С 7.7 разработчики часто сталкиваются с ситуацией, когда итоговая таблица выводит неполный остаток. Например, по данным регистра товар пришел тремя партиями общим количеством 8 штук, но при обходе группировок запрос возвращает «1» — количество из первой поступившей партии.

Проанализируем причины возникновения этой проблемы, разберем ошибку в алгоритме и рассмотрим правильные способы получения итоговых остатков и суммовых показателей.

Анализ исходного кода и причины ошибки

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


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

Пока Запрос.Группировка(1) = 1 Цикл
    Пока Запрос.Группировка(2) = 1 Цикл
        СводнаяТаблица.НоваяСтрока();
        СводнаяТаблица.Номенклатура = Запрос.Товар;
        СводнаяТаблица.Количество = Запрос.Колво; // Ошибка здесь!
    КонецЦикла;
КонецЦикла;

Выясним, почему Запрос.Колво выводит значение 1 вместо 8. В языке запросов 1С 7.7 прямое обращение к переменной регистра (в данном случае Запрос.Колво или Запрос.Цена), для которой не определена агрегатная функция и по которой не задана группировка, возвращает значение реквизита только из первой найденной записи (движения) внутри текущей группы.

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

Исправление ошибки обхода группировки

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

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


Пока Запрос.Группировка(1) = 1 Цикл
    Пока Запрос.Группировка(2) = 1 Цикл
        СводнаяТаблица.НоваяСтрока();
        СводнаяТаблица.Номенклатура = Запрос.Товар;
        // Обращаемся к агрегатной функции запроса:
        СводнаяТаблица.Количество = Запрос.ТовОстаток;
    КонецЦикла;
КонецЦикла;

Расчет суммовых показателей и средней цены

Рассмотрим еще один важный технический момент. Если номенклатура поступала партиями с различной учетной ценой, то умножение Запрос.Цена * Запрос.ТовОстаток приведет к ошибке в учете. Переменная Запрос.Цена вернет стоимость первой попавшейся партии, что исказит итоговую сумму остатка.

Для корректного расчета сумм и средних цен применим следующий подход:

  1. Добавим в текст запроса функцию расчета остатка по суммовому ресурсу регистра: Функция СуммаОст = КонОст(Сумма);.
  2. При обходе результатов будем получать общую сумму через Запрос.СуммаОст.
  3. Расчетную среднюю цену определим делением общей суммы остатка на количество: Запрос.СуммаОст / Запрос.ТовОстаток.

Посмотрим на пример правильного текста запроса:


ТекстЗапроса = "
|Период по ДатаОст;
|Обрабатывать НеПомеченныеНаУдаление;
|Фирма = Регистр.СкладУчетПарт.Фирма;
|Товар = Регистр.СкладУчетПарт.Номенклатура;
|Колво = Регистр.СкладУчетПарт.Количество;
|Сумма = Регистр.СкладУчетПарт.Сумма;
|Функция ТовОстаток = КонОст(Колво);
|Функция СуммаОстаток = КонОст(Сумма);
|Группировка Фирма без групп;
|Группировка Товар без групп;
|Условие(Фирма в СписокФирм);
|";

Теперь проанализируем заполнение таблицы значений с расчетом показателей:


Пока Запрос.Группировка("Фирма") = 1 Цикл
    Пока Запрос.Группировка("Товар") = 1 Цикл
        ОстКолво = Запрос.ТовОстаток;
        ОстСумма = Запрос.СуммаОстаток;
        СредняяЦена = ?(ОстКолво <> 0, ОстСумма / ОстКолво, 0);
        
        СводнаяТаблица.НоваяСтрока();
        СводнаяТаблица.Номенклатура = Запрос.Товар;
        СводнаяТаблица.Количество = ОстКолво;
        СводнаяТаблица.Цена = СредняяЦена;
        СводнаяТаблица.Сумма = ОстСумма;
    КонецЦикла;
КонецЦикла;

Рекомендации по оптимизации работы с запросами

Рассмотрим правила, которые помогут избежать ошибок и повысят скорость работы обработок в 1С 7.7:

  1. Формируйте колонки таблицы значений до цикла: Вызовы метода НоваяКолонка() внутри циклов выборки изменяют структуру таблицы на лету, что приводит к сдвигу индексов и некорректной записи значений. Структура колонок должна создаваться заранее.
  2. Переносите условия в текст запроса: Вместо проверки условий в коде (например, Если ФирмаОбщ = Фирма1...) используйте конструкцию Условие() в тексте запроса. Это снизит объем данных, передаваемых из БД.
  3. Оптимизируйте период: Если требуются только конечные остатки на конкретную дату, указывайте Период по ДатаОст; без начальной даты Период с.... Это избавит платформу от лишнего расчета оборотов за период.
← На главную