Как изменить запрос в СКД, чтобы в отчет выводилась вся номенклатура базы

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Анализ проблемы: почему данные пропадают

Проанализируем исходную ситуацию. В отчете используются временные таблицы (ВТ) и объединения данных из регистров СвободныеОстатки, ТоварыКОтгрузке, ГрафикПоступленияТоваров и других. Основной запрос выбирает данные из этих ВТ. Поскольку выборка идет «от данных» (то есть из таблиц с остатками), позиции номенклатуры, по которым остаток равен нулю и нет запланированных приходов, просто не попадают в выборку. Чтобы исправить это, нам необходимо применить принцип «мастер-таблицы», где в роли главной таблицы выступит справочник Номенклатура.

Решение №1: Использование Левого соединения в основном запросе

Самый надежный способ — сделать справочник Номенклатура левым операндом в соединении. Разберем по шагам, как это реализовать в тексте запроса. Нам нужно выбрать все ссылки из справочника и к ним «приклеить» результаты наших расчетов.

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


ВЫБРАТЬ
    спрНоменклатура.Ссылка КАК Номенклатура,
    ЕСТЬNULL(Данные.ВНаличии, 0) КАК ВНаличии,
    ЕСТЬNULL(Данные.ПриходОсновной, 0) КАК ПриходОсновной,
    ЕСТЬNULL(Данные.РасходОсновной, 0) КАК РасходОсновной
ИЗ
    Справочник.Номенклатура КАК спрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ (
    // Здесь располагается ваш исходный объединяющий запрос
    ВЫБРАТЬ
        Набор.Номенклатура КАК Номенклатура,
        СУММА(Набор.ВНаличии) КАК ВНаличии,
        СУММА(Набор.ПриходОсновной) КАК ПриходОсновной,
        СУММА(Набор.РасходОсновной) КАК РасходОсновной
    ИЗ (
        ВЫБРАТЬ Таблица.Номенклатура, Таблица.ВНаличии ... ИЗ ВтСвободныеОстатки КАК Таблица
        ОБЪЕДИНИТЬ ВСЕ
        ВЫБРАТЬ Таблица.Номенклатура, 0 ... ИЗ РегистрНакопления.ГрафикПоступленияТоваров.Остатки(...)
    ) КАК Набор
    СГРУППИРОВАТЬ ПО Набор.Номенклатура
) КАК Данные
ПО спрНоменклатура.Ссылка = Данные.Номенклатура
ГДЕ
    НЕ спрНоменклатура.ЭтоГруппа

Важный нюанс: при использовании такого подхода обязательно нужно использовать функцию ЕСТЬNULL для всех числовых полей, приходящих из правой таблицы (данных регистров). Если этого не сделать, в отчете вместо нулей будут пустые ячейки (значения NULL), что затруднит дальнейшие расчеты в вычисляемых полях или ресурсах СКД.

Работа над ошибками: псевдонимы и структура

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

Рассмотрим правильный синтаксис окончания запроса:


...
И ТвойРегистр.ДатаДоступности = ДАТАВРЕМЯ(1, 1, 1)
) КАК Данные // Вот этот псевдоним "Данные" обязателен!
ПО спрНоменклатура.Ссылка = Данные.Номенклатура

Решение №2: Связи наборов данных в конструкторе СКД

Если отчет содержит три и более наборов данных, иногда проще не «раздувать» один запрос гигантским левым соединением, а настроить связи непосредственно на вкладке «Связи наборов данных». Рассмотрим, как это сделать правильно:

  1. Создадим новый набор данных-запрос (назовем его НаборДанных_Номенклатура).
  2. В тексте запроса выберем только Номенклатура.Ссылка и необходимые реквизиты (артикул, код).
  3. Сделаем этот набор «ведущим». На вкладке связей в колонке «Источник связи» укажем наш новый набор со справочником.
  4. В колонке «Приемник связи» укажем наборы, содержащие данные по остаткам и заказам.
  5. Условие связи установим по полю Номенклатура.

Внимание: При таком подходе, если в настройках отчета пользователь установит отбор по Складу, то позиции номенклатуры без остатков на этом складе могут снова исчезнуть. Это происходит из-за того, что СКД накладывает отбор на весь результат компоновки. Чтобы этого избежать, используйте в настройках поля роль «Игнорировать значения NULL» или накладывайте отборы непосредственно в параметрах виртуальных таблиц запроса.

Особенности работы с характеристиками и сегментами

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

Также в исходном коде автора упоминается таблица ОтборПоСегментуНоменклатуры. Рассмотрим, как не потерять этот фильтр:

Если мы выводим «всю номенклатуру», но при этом включен фильтр по сегменту, мы должны выводить всю номенклатуру внутри этого сегмента. Следовательно, левое соединение должно начинаться не просто со справочника, а с таблицы сегмента (если фильтр активен).

Рекомендации по оптимизации

Вывод всей номенклатуры (которой в базе может быть более 100 000 позиций) существенно замедляет отчет. Проанализируем способы ускорения:

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

← На главную