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

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

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

Разбор проблемы: почему запрос двоит строки

Проанализируем типичную ситуацию. Допустим, мы хотим получить данные из регистра остатков, разделяя их на две колонки в зависимости от наименования характеристики. Если мы просто добавим конструкцию ВЫБОР в список полей, платформа будет вынуждена выводить разные значения для каждого условия. Основная ошибка заключается в том, что поле, содержащее условие (например, ХарактеристикаНоменклатуры), или само вычисляемое поле добавляется в секцию СГРУППИРОВАТЬ ПО.

Рассмотрим пример ошибочного кода:


ВЫБРАТЬ
    Товары.Номенклатура КАК Товар,
    ВЫБОР
        КОГДА Товары.Характеристика.Наименование = "Да" ТОГДА Товары.КоличествоОстаток
        ИНАЧЕ 0
    КОНЕЦ КАК Импорт,
    ВЫБОР
        КОГДА Товары.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) ТОГДА Товары.КоличествоОстаток
        ИНАЧЕ 0
    КОНЕЦ КАК НеИмпорт
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Товары
СГРУППИРОВАТЬ ПО
    Товары.Номенклатура,
    Товары.КоличествоОстаток, // ОШИБКА: поле остатка в группировке
    Товары.Характеристика // ОШИБКА: характеристика заставляет запрос детализировать строки

В данном случае, если у товара есть и «пустая» характеристика, и характеристика с наименованием «Да», система создаст две уникальные комбинации для группировки, что приведет к появлению двух строк в результате.

Решение №1: Использование агрегатных функций внутри ВЫБОР

Самый эффективный и правильный способ «схлопнуть» строки — это обернуть конструкцию ВЫБОР в агрегатную функцию СУММА. При этом важно убрать все поля, отвечающие за количество и уникальные признаки (характеристики), из секции СГРУППИРОВАТЬ ПО. В группировке должны остаться только те поля, которые идентифицируют саму строку (например, Номенклатура и Артикул).

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

  1. Помещаем логику разделения данных внутрь функции СУММА.
  2. В секции СГРУППИРОВАТЬ ПО оставляем только ссылку на товар и его реквизиты (Артикул, ТипЦен и т.д.).
  3. Убеждаемся, что мы не используем поля характеристик или регистра остатков в списке группировки, если они не должны разделять строки.

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


ВЫБРАТЬ
    СпрНоменклатура.Ссылка КАК Товар,
    СпрНоменклатура.Артикул КАК Артикул,
    СУММА(ВЫБОР
            КОГДА ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры.Наименование = "Да"
                ТОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)
            ИНАЧЕ 0
        КОНЕЦ) КАК Импорт,
    СУММА(ВЫБОР
            КОГДА ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)
                ТОГДА ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)
            ИНАЧЕ 0
        КОНЕЦ) КАК НеИмпорт,
    СУММА(ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)) КАК ОбщийОстаток
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
        ПО ТоварыНаСкладахОстатки.Номенклатура = СпрНоменклатура.Ссылка
СГРУППИРОВАТЬ ПО
    СпрНоменклатура.Ссылка,
    СпрНоменклатура.Артикул

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

Решение №2: Использование временных таблиц для оптимизации

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

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

  1. Сначала выберем все остатки во временную таблицу, выполнив группировку и расчет «Импорта» и «НеИмпорта» на лету.
  2. Проиндексируем временную таблицу по полю Номенклатура.
  3. Вторым шагом соединим готовую свернутую таблицу со справочником номенклатуры и ценами.

Пример реализации через временную таблицу:


ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    СУММА(ВЫБОР КОГДА Остатки.Характеристика.Наименование = "Да" ТОГДА Остатки.КоличествоОстаток ИНАЧЕ 0 КОНЕЦ) КАК КолИмпорт,
    СУММА(ВЫБОР КОГДА Остатки.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) ТОГДА Остатки.КоличествоОстаток ИНАЧЕ 0 КОНЕЦ) КАК КолНеИмпорт
ПОМЕСТИТЬ ВТ_СвернутыеОстатки
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
СГРУППИРОВАТЬ ПО
    Остатки.Номенклатура;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Спр.Ссылка КАК Товар,
    Спр.Артикул КАК Артикул,
    ЕСТЬNULL(ВТ.КолИмпорт, 0) КАК Импорт,
    ЕСТЬNULL(ВТ.КолНеИмпорт, 0) КАК НеИмпорт,
    Цены.Цена КАК ЦенаРозничная
ИЗ
    Справочник.Номенклатура КАК Спр
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СвернутыеОстатки КАК ВТ ПО Спр.Ссылка = ВТ.Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен) КАК Цены ПО Спр.Ссылка = Цены.Номенклатура

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

Особенности использования ОБЪЕДИНИТЬ ВСЕ в Системе компоновки данных (СКД)

Иногда программисты пытаются решить задачу через ОБЪЕДИНИТЬ ВСЕ, как было предложено в одном из сообщений форума. Выясним причину, почему это может не сработать в СКД. Когда мы объединяем два запроса, у них должна быть идентичная структура колонок. Если в первом запросе есть поле Импорт, а во втором его нет — возникнет ошибка или поле пропадет.

Чтобы правильно использовать объединение, нужно создавать «пустышки»:


ВЫБРАТЬ Номенклатура, КоличествоОстаток КАК Импорт, 0 КАК НеИмпорт ИЗ ... ГДЕ Характеристика.Наименование = "Да"
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Номенклатура, 0 КАК Импорт, КоличествоОстаток КАК НеИмпорт ИЗ ... ГДЕ Характеристика = ПустаяСсылка

Однако даже после объединения строки останутся разделенными (в одной строке будет заполнен Импорт, в другой — НеИмпорт). Чтобы окончательно их свернуть, такой запрос нужно поместить во вложенный запрос или временную таблицу и снова применить СУММА и СГРУППИРОВАТЬ ПО.

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

Проанализируем использование условия ХарактеристикаНоменклатуры.Наименование = "Да". Это строковое сравнение, которое чувствительно к регистру и пробелам. Рассмотрим более надежные способы:

  1. Дополнительные реквизиты: Вместо поиска по имени лучше использовать дополнительные сведения или реквизиты характеристик. В запросе это будет выглядеть как обращение к табличной части или значению свойства, что более надежно.
  2. Предопределенные элементы: Если признак «Импорт» фиксирован, можно использовать логику соответствия конкретным ссылкам, если они известны заранее (хотя для характеристик это редкость).

Подводя итог, можно сказать: для сворачивания товара в одну строку всегда используйте агрегатные функции (СУММА, МАКСИМУМ) и следите за тем, чтобы в секции СГРУППИРОВАТЬ ПО не было полей, которые создают лишнюю детализацию. В 90% случаев перемещение ВЫБОР внутрь СУММА решает проблему дублирования строк.

← На главную