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

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

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

Постановка задачи и анализ структуры запроса

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

Использование левого соединения: почему это стандарт

В сообщениях форума часто возникает вопрос о использовании ПРАВОГО СОЕДИНЕНИЯ. Проанализируем, почему опытные разработчики рекомендуют использовать именно ЛЕВОЕ СОЕДИНЕНИЕ. С точки зрения логики СУБД, эти соединения зеркальны, однако в 1С принято брать за основу «ведущую» таблицу (в нашем случае это справочник Номенклатура) и присоединять к ней дополнительные данные (цены). Это делает запрос гораздо более читаемым и понятным для других программистов.

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


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

Оптимизация производительности: параметры виртуальной таблицы

Проанализируем приведенный выше код. С точки зрения производительности у него есть существенный недостаток. Если в регистре сведений ЦеныНоменклатуры хранятся миллионы записей, система сначала получит срез последних цен для всех товаров, а только потом отсечет лишние по условию ГДЕ. Это может привести к значительным задержкам.

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


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

Важный нюанс: условие В ИЕРАРХИИ в параметрах виртуальной таблицы заставляет платформу 1С ограничить выборку из регистра еще на этапе формирования SQL-запроса. Это критически важно для работы с большими базами данных.

Обработка значений NULL

Разберем ситуацию, когда для товара цена еще не была установлена. При использовании ЛЕВОГО СОЕДИНЕНИЯ в полях цены для таких строк вернется значение NULL. Чтобы ваш отчет или алгоритм не «сломался» при попытке математической операции, всегда используйте функцию ЕСТЬNULL(). Рассмотрим подробнее: функция принимает два аргумента — проверяемое поле и значение, которое нужно вернуть, если поле равно NULL (например, 0).

Работа со сложными фильтрами через временные таблицы

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

  1. Создаем временную таблицу ВТ_СписокНоменклатуры, куда помещаем только ссылки на нужные нам товары.
  2. Вторым пакетом запроса выбираем данные, соединяя ВТ_СписокНоменклатуры и СрезПоследних.
  3. В параметрах СрезПоследних указываем фильтр: Номенклатура В (ВЫБРАТЬ Ссылка ИЗ ВТ_СписокНоменклатуры).

Такой подход позволяет системе максимально эффективно использовать индексы таблиц и минимизировать объем передаваемых данных.

Периодичность и дата среза

Посмотрим на параметр &Период. Если вы не передадите дату в виртуальную таблицу, 1С вернет срез на «самое текущее» время (на текущую секунду). Однако в запросах, работающих внутри документов или отчетов за прошлые периоды, крайне важно явно указывать дату. Например, &ДатаОтчета или КОНЕЦДНЯ(&ДатаДокумента), чтобы данные были консистентными и соответствовали моменту времени, за который формируется отчет.

Влияние измерений регистра на результат

Проанализируем структуру регистра цен. Если в регистре помимо Номенклатуры есть другие измерения (например, Характеристика или ВидЦены), а вы их не указали в фильтрах, запрос может вернуть несколько строк на одну позицию номенклатуры. Это приведет к «раздуванию» результата. Чтобы этого избежать, обязательно накладывайте фильтр по ВидуЦены в параметрах виртуальной таблицы:


РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, 
    Номенклатура В ИЕРАРХИИ(&Родитель) И ВидЦены = &НужныйВидЦены) КАК Цены

Подведем итоги

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

  1. Используем ЛЕВОЕ СОЕДИНЕНИЕ от таблицы справочника к таблице цен.
  2. Все условия по возможности выносим в параметры виртуальной таблицы (&Период, &Условие).
  3. Всегда обрабатываем пустые значения цен функцией ЕСТЬNULL.

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

← На главную