Как работают ключевые слова «Все» и «ВошедшиеВЗапрос» в запросах 1С 7.7

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

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

В этой статье мы подробно разберем, что означают эти ключевые слова, как они работают «под капотом» платформы, для решения каких задач они предназначены, а также рассмотрим подводные камни, связанные с производительностью системы.

Что означает ключевое слово «Все» в группировке?

Рассмотрим стандартный запрос, который выбирает данные из регистра остатков или оборотов. Если мы пишем обычную группировку без дополнительных ключевых слов:


|Группировка Номенклатура Без Групп;
|Группировка Комиссионер Без Групп;

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

Если же мы модифицируем запрос и добавим ключевое слово Все:

|Группировка Комиссионер Без Групп Все;

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

Иными словами, ключевое слово Все заставляет систему брать за основу не таблицу движений регистра, а саму таблицу справочника, указанного в группировке, и «накладывать» на нее данные регистра. Это аналог SQL-конструкции LEFT OUTER JOIN, где левой таблицей выступает весь справочник.

Что означает ключевое слово «ВошедшиеВЗапрос»?

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

Для решения этой задачи применяется связка Все ВошедшиеВЗапрос. Например:

|Группировка Комиссионер Без Групп Все ВошедшиеВЗапрос;

Этот механизм работает следующим образом:

  1. Сначала платформа анализирует весь запрос и формирует список только тех контрагентов, по которым в выбранном периоде есть хотя бы одно ненулевое движение (по любой номенклатуре).
  2. Затем при обходе группировок для каждой номенклатурной позиции система будет возвращать строго этот фиксированный список контрагентов.
  3. Если по конкретному товару у данного контрагента движения отсутствовали, запрос вернет нулевое значение ресурса, но сама строка (или колонка) в выборке останется.

Практический пример: построение двумерной «шахматки» (кросс-таблицы)

Классический пример использования ключевого слова ВошедшиеВЗапрос — это построение «шахматки» (кросс-таблицы), где в строках выводится номенклатура, а в колонках вправо строятся покупатели.

Если обходить выборку обычным способом, то для каждого товара будет выводиться свой собственный список покупателей. Это сделает невозможным вывод отчета простым присоединением секций таблицы в цикле, так как колонки будут постоянно смещаться. Использование Все ВошедшиеВЗапрос гарантирует, что для каждой строки номенклатуры состав колонок-покупателей будет абсолютно идентичным.

Рассмотрим пример программного кода для реализации такого отчета:


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

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Предупреждение("Ошибка выполнения запроса!");
        Возврат;
    КонецЕсли;

    Таб = СоздатьОбъект("Таблица");
    Таб.ВывестиСекцию("Шапка_ЛеваяЧасть"); // Выводит ячейку "Товар / Контрагент"

    // Шаг 1. Заполняем горизонтальную шапку отчета (колонки покупателей)
    // Для этого временно обходим вторую группировку, чтобы вывести имена клиентов
    Пока Запрос.Группировка(2) = 1 Цикл
        Таб.ПрисоединитьСекцию("Шапка_КолонкаПокупателя");
    КонецЦикла;

    // Шаг 2. Выводим строки с данными
    Пока Запрос.Группировка(1) = 1 Цикл
        // Выводим левую колонку строки с названием товара
        Таб.ВывестиСекцию("Строка_Товар");
        
        // Обходим покупателей. Благодаря 'Все ВошедшиеВЗапрос' 
        // для каждого товара обход вернет один и тот же набор покупателей
        Пока Запрос.Группировка(2) = 1 Цикл
            СуммаПродажи = Запрос.ВсегоВыручка; // Здесь будет реальная сумма или 0
            Таб.ПрисоединитьСекцию("Строка_ЯчейкаДанных");
        КонецЦикла;
    КонецЦикла;

    Таб.Показать("Шахматка продаж");
КонецПроцедуры

Важные технические нюансы и подводные камни

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

1. Работа с временными интервалами. Ключевое слово Все можно использовать не только для справочников, но и для временных группировок (Период, Год, Месяц, Декада, Неделя, День). Например, конструкция Группировка День Все; гарантирует, что в выборку запроса попадут абсолютно все календарные дни из указанного в запросе периода, даже если в эти дни в системе не было зарегистрировано ни одного документа.

2. Взаимодействие с оператором «Условие». Поведение запроса существенно зависит от того, на какое именно поле наложено условие:

3. Проблема падения производительности (SQL-версии). Движок запросов 1С 7.7 не оптимизирован для трансляции сложных группировок со словом Все в эффективный SQL-код. Вместо выполнения одного быстрого запроса СУБД начинает строить декартово произведение (Cartesian Product) таблиц в оперативной памяти сервера или через временные таблицы на диске. Если в справочнике номенклатуры содержится более 10 000 элементов, а в справочнике контрагентов — более 5 000, выполнение такого запроса может полностью заблокировать работу базы данных или привести к аварийному завершению процесса из-за нехватки памяти.

Как эти проблемы обходили профессиональные разработчики?

Чтобы избежать зависания системы на больших объемах данных, опытные программисты 1С 7.7 отказывались от использования штатного механизма Все в пользу альтернативных вариантов:

Решение аналогичных задач в 1С:Предприятие 8

В современных версиях платформы 1С v8.3 разработчики полностью отказались от неоднозначных конструкций Все и ВошедшиеВЗапрос. Теперь эти задачи решаются на качественно другом уровне:

← На главную