Как реализовать левое соединение в запросах 1С 7.7 и вывести все элементы справочника

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

В современной разработке на платформе 1С 8.x мы привыкли к гибкости языка Query (SQL-подобного), где конструкция ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) является базовой. Однако в среде 1С:Предприятие 7.7 механизмы работы с запросами существенно отличаются. Часто перед разработчиком встает задача: вывести полный список номенклатуры из справочника и пристыковать к нему данные по остаткам из регистра. Если остатка нет, система должна вывести ноль, но сам товар не должен исчезнуть из отчета.

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

Механизм «Левого соединения» через ключевое слово «Все»

В 1С 7.7 аналог LEFT JOIN реализуется не в секции связей (которой нет в явном виде), а через определение состава группировки. По умолчанию запрос 1С 7.7 работает как INNER JOIN: в результат попадают только те записи, для которых есть соответствующие данные и в справочнике, и в регистре (или другом источнике данных). Чтобы изменить это поведение, необходимо использовать ключевое слово Все (или ALL в англоязычном варианте).

Рассмотрим базовый пример. Допустим, нам нужно получить все товары и их конечные остатки. Проанализируем структуру запроса:


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

Обратите внимание на строку Группировка Товар Все;. Именно слово Все указывает системе, что в итоговую выборку должны попасть абсолютно все элементы справочника Номенклатура, даже если по ним не было движений или остатков в регистре ОстаткиТоваров.

Удаление групп из иерархии: флаг «Без Групп»

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

Добавим условие исключения групп непосредственно в описание группировки:

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

Комбинация Без Групп Все позволяет решить сразу две задачи:

  1. Оставить только конечные элементы (карточки товара), исключив папки.
  2. Сохранить левое соединение, выведя даже те карточки, по которым остаток равен нулю.

Проблема фильтрации и исключения групп

Часто возникает необходимость отсечь определенную ветку справочника (например, категорию «Услуги» или «Брак»). Казалось бы, достаточно добавить простое условие НЕ (Товар в ВыбГруппа). Однако здесь кроется главная ловушка встроенных запросов 1С 7.7.

Разберем ситуацию: если вы используете Группировка Товар Все и одновременно ставите условие НЕ (Товар в ВыбГруппа), вы можете столкнуться с тем, что товары без остатков начнут исчезать или, наоборот, фильтр перестанет работать корректно. Это связано с тем, как движок 1С 7.7 интерпретирует логические условия при построении временных таблиц в памяти.

Рассмотрим наиболее надежный способ фильтрации, который предложили участники обсуждения:


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

Важный нюанс: использование функции ПринадлежитГруппе() внутри условия запроса может замедлить выполнение на больших справочниках, особенно в файловой версии (DBF). Если производительность критична, а структура справочника позволяет, можно использовать проверку родителя: Условие (Товар.Родитель <> ВыбГруппа), но помните, что это сработает только для элементов, находящихся непосредственно внутри ВыбГруппа, без учета вложенности.

Особенности работы с SQL-версией 1С 7.7

Проанализируем техническую сторону работы запроса в среде SQL. В 1С 7.7 при использовании стандартного языка запросов есть известная особенность с оператором НЕ. Иногда он некорректно обрабатывается транслятором при формировании SQL-кода. Именно поэтому опытные разработчики рекомендуют использовать сравнение с нулем (как в примере выше: = 0) вместо явного отрицания НЕ, если это возможно.

Если же база данных имеет внушительный объем и штатные запросы работают слишком медленно, рекомендуется обратить внимание на прямые запросы (Direct SQL). Это технология, реализуемая с помощью внешних компонент (например, 1С++). В прямом запросе вы сможете написать классический SQL:


SELECT 
    Nom.ID as [Товар $Справочник.Номенклатура],
    ISNULL(Reg.Quantity, 0) as Остаток
FROM 
    $Справочник.Номенклатура as Nom
LEFT JOIN 
    (SELECT ItemID, SUM(Balance) as Quantity FROM RegTable WHERE ...) as Reg ON Nom.ID = Reg.ItemID
WHERE 
    Nom.ParentID <> :ExcludeGroup

Однако для быстрой разработки простых отчетов штатный механизм с ключевым словом Все остается незаменимым инструментом.

Итоговый алгоритм действий

Подведем итог и составим пошаговый план реализации задачи:

  1. Определите источник данных для справочника и регистра в одной переменной запроса (через запятую).
  2. Обязательно определите ресурс через Функция (например, КонОст или Сумма), чтобы система знала, что именно нужно агрегировать.
  3. В секции группировки укажите Все — это активирует режим LEFT JOIN.
  4. Для исключения групп используйте метод ПринадлежитГруппе() = 0 в секции Условие.
  5. Если в отчет не должны попадать сами группы (папки), добавьте Без Групп.

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

← На главную