Как в запросе 1С правильно получить базовую цену номенклатуры

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

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

Понимание структуры хранения цен

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

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

Способ 1. Использование виртуальной таблицы СрезПоследних

Рассмотрим самый правильный и оптимизированный способ получения актуальной цены. Использование виртуальной таблицы СрезПоследних позволяет системе самостоятельно вычислить наиболее актуальную запись на указанную дату.

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


ВЫБРАТЬ
    ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура,
    ЦеныНоменклатурыСрезПоследних.Цена КАК Цена,
    ЦеныНоменклатурыСрезПоследних.Валюта КАК Валюта
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен) КАК ЦеныНоменклатурыСрезПоследних

Важный нюанс: Обратите внимание, что условие по типу цен передается непосредственно в параметры виртуальной таблицы. Это критически важно для производительности. Если мы напишем условие в секции ГДЕ, система сначала получит последние цены всех типов для всей номенклатуры, а потом отфильтрует их. Передача параметра внутрь таблицы заставляет СУБД сразу выбирать только нужные записи.

Способ 2. Получение цены через левое соединение со справочником Номенклатура

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


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

Использование функции ЕСТЬNULL позволяет нам заменить пустое значение (если цена не найдена) на ноль, что полезно для дальнейших математических вычислений в отчете.

Разбор типичных ошибок: почему не стоит использовать МАКСИМУМ

В процессе обсуждения часто предлагается использовать агрегатную функцию МАКСИМУМ(Цена) при группировке. Проанализируем ситуацию: если в физической таблице регистра накоплено несколько записей по одному товару и типу цены (например, в январе цена была 100 руб., а в феврале стала 80 руб.), то функция МАКСИМУМ вернет 100 руб. Однако актуальная цена — 80 руб.

Никогда не используйте МАКСИМУМ для получения последней цены, если только ваша задача не состоит именно в поиске пиковой стоимости за период. Для получения актуальных данных на временной оси предназначен только СрезПоследних.

Как правильно передать тип цен в запрос

Существует несколько подходов к определению "Базовой" цены в коде:

  1. Поиск по коду или наименованию: Самый простой, но рискованный метод. Если бухгалтер изменит название "Базовая" на "Основная покупная", код перестанет работать. &ТипЦен = Справочники.ТипыЦенНоменклатуры.НайтиПоКоду("000000001");
  2. Использование параметров в СКД: Лучший вариант для отчетов. Вынесите выбор типа цены на вкладку параметров, чтобы пользователь сам указал, какую цену считать базовой.
  3. Программная установка в модуле:
    
    Процедура ПриКомпоновкеРезультата(ИзменныеНастройки, ДанныеРасшифровки, СтандартнаяОбработка)
        ПараметрТипЦен = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("ТипЦен");
        Если ПараметрТипЦен <> Неопределено Тогда
            ПараметрТипЦен.Значение = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Базовая");
            ПараметрТипЦен.Использование = Истина;
        КонецЕсли;
    КонецПроцедуры
    

Дополнительные факторы: Характеристики и Валюты

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

Также не забывайте про Валюту. Цена в регистре хранится в той валюте, в которой был оформлен документ установки цен. Если базовая цена задана в долларах, а отчет должен быть в рублях, вам потребуется дополнительно соединить результат запроса с регистром сведений КурсыВалют и выполнить пересчет по формуле: Цена * Курс / Кратность.

Итоговый оптимальный шаблон запроса

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


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

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

← На главную