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

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

При разработке отчетов в 1С 7.7 разработчики часто сталкиваются с задачей вывести полную номенклатуру (включая позиции с нулевыми остатками и отсутствием оборотов), наложив при этом отбор по конкретным реквизитам — например, по поставщику или группе товаров. Добавление конструкций вида Группировка Номенклатура Все; может приводить к неожиданному результату: запрос либо выводит вообще весь справочник без учета фильтров, либо полностью отсекает позиции с нулевыми остатками.

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

Выясним причину проблемы

Посмотрим на исходную структуру запроса, в которой возникает ошибка:


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

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

  1. Переменная связана только с регистрами: В тексте запроса переменная Поставщик вычисляется исключительно через реквизиты регистров накопителей (Регистр.ОстаткиТМЦ.Номенклатура.Поставщик). Если по номенклатуре не было движений в указанных регистрах за период, значения из регистров для нее не формируются (равны пустой ссылке).
  2. Особенности работы ключевого слова Все: Модификатор Все в конструкции Группировка заставляет запрос перебирать весь справочник Номенклатура. Однако предложение Условие накладывает жесткий фильтр. Для товаров без движений значение поля Поставщик получается незаполненным, из-за чего проверка Поставщик = ВбрПоставщик дает ложный результат и эти строки отсекаются.

Способ 1. Привязка переменных к справочнику номенклатуры

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

Разберем по шагам изменения в тексте запроса:

  1. В источнике переменной Номенклатура первым указанием пропишем элемент справочника: Справочник.Номенклатура.ТекущийЭлемент.
  2. Переменную Поставщик определим напрямую через реквизит справочника: Справочник.Номенклатура.Поставщик.

В итоге текст запроса принимает следующий вид:


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

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

Способ 2. Использование модификатора ВсеВошедшиеВЗапрос и Списка Значений

Другой надежный подход — предварительно отфильтровать номенклатуру средствами языка 1С 7.7 и передать готовый список элементов в запрос.

Разберем реализацию метода:

  1. Перед выполнением запроса формируем объект СписокЗначений и заполняем его элементами справочника, соответствующими отбору по поставщику.
  2. В тексте запроса используем условие Условие (Номенклатура в СписокПоставщика);.
  3. В описании группировки применяем модификатор ВсеВошедшиеВЗапрос вместо Все.

СписокПоставщика = СоздатьОбъект("СписокЗначений");
СпрН = СоздатьОбъект("Справочник.Номенклатура");
СпрН.ВыбратьЭлементы();
Пока СпрН.ПолучитьЭлемент() = 1 Цикл
    Если СпрН.ЭтоГруппа() = 1 Тогда 
        Продолжить; 
    КонецЕсли;
    Если СпрН.Поставщик = ВбрПоставщик Тогда
        СписокПоставщика.ДобавитьЗначение(СпрН.ТекущийЭлемент());
    КонецЕсли;
КонецЦикл;

ТекстЗапроса = "
|Период с ДатаНачала по ДатаКонца;     
|Номенклатура = Справочник.Номенклатура.ТекущийЭлемент, Регистр.ОстаткиТМЦ.Номенклатура;
|Количество = Регистр.ОстаткиТМЦ.Количество;
|Функция КоличествоКонОст = КонОст(Количество);
|Группировка Номенклатура Без Групп ВсеВошедшиеВЗапрос;
|Условие (Номенклатура в СписокПоставщика);
|";

Конструкция ВсеВошедшиеВЗапрос гарантирует, что в итоговую выборку попадут абсолютно все элементы из переданного списка отбора, независимо от наличия движений по регистрам.

Способ 3. Фильтрация при обходе результатов запроса

Если изменять структуру связей в запросе нецелесообразно, можно убрать условие отбора по поставщику из текста запроса и перенести проверку в цикл выгрузки результатов.

Пример кода обработки:


// В запросе оставляем группировку с модификатором Все, но убираем Условие по Поставщику
|Группировка Номенклатура Без Групп Все;
|Условие (Фирма в ВбрФирма);

// При обходе проверяем условие программно:
Запрос.Выполнить(ТекстЗапроса);
Пока Запрос.Группировка("Номенклатура") = 1 Цикл
    Если ЗначениеЗаполнено(ВбрПоставщик) = 1 Тогда
        Если Запрос.Номенклатура.Поставщик <> ВбрПоставщик Тогда
            Продолжить; // Пропускаем товары других поставщиков
        КонецЕсли;
    КонецЕсли;
    
    // Обработка строк отчета
КонецЦикл;

Способ 4. Использование прямых SQL-запросов (1С++ / Direct SQL)

В сложных отчетах штатный механизм черных запросов 1С 7.7 может работать медленно при соединении большого количества регистров и справочников. Для решения проблем производительности и построения сложных внешних соединений (LEFT JOIN) рекомендуется использовать прямые SQL-запросы к базе данных 1С 7.7 через внешнюю компоненту 1С++.

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

← На главную