Одной из наиболее частых задач при разработке в среде 1С:Предприятие 8 является получение актуальных цен для списка товаров. Несмотря на кажущуюся простоту, здесь существует множество нюансов, связанных с производительностью, правильным выбором типа соединения и фильтрацией данных. В этой статье мы разберем, как эффективно соединить справочник Номенклатура и виртуальную таблицу СрезПоследних регистра сведений, а также выясним, почему «правое соединение» обычно оказывается не лучшим выбором.
Представим типичную ситуацию: нам необходимо выбрать всю номенклатуру из определенной группы (иерархии) и сопоставить ей последние установленные цены. Если цены для товара нет, мы все равно должны увидеть товар в списке, но с пустым или нулевым значением цены. Рассмотрим, как это реализовать правильно, соблюдая стандарты разработки 1С.
В сообщениях форума часто возникает вопрос о использовании ПРАВОГО СОЕДИНЕНИЯ. Проанализируем, почему опытные разработчики рекомендуют использовать именно ЛЕВОЕ СОЕДИНЕНИЕ. С точки зрения логики СУБД, эти соединения зеркальны, однако в 1С принято брать за основу «ведущую» таблицу (в нашем случае это справочник Номенклатура) и присоединять к ней дополнительные данные (цены). Это делает запрос гораздо более читаемым и понятным для других программистов.
Рассмотрим базовый пример кода запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
Номенклатура.Код КАК SKU_Code,
ЕСТЬNULL(Цены.Цена, 0) КАК АктуальнаяЦена
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены
ПО
Номенклатура.Ссылка = Цены.Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ(&Родитель)
И НЕ Номенклатура.ЭтоГруппа
Проанализируем приведенный выше код. С точки зрения производительности у него есть существенный недостаток. Если в регистре сведений ЦеныНоменклатуры хранятся миллионы записей, система сначала получит срез последних цен для всех товаров, а только потом отсечет лишние по условию ГДЕ. Это может привести к значительным задержкам.
Чтобы избежать лишней нагрузки, необходимо перенести условия фильтрации непосредственно в параметры виртуальной таблицы. Выясним, как это изменить:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
Номенклатура.Код КАК SKU_Code,
ЕСТЬNULL(Цены.Цена, 0) КАК АктуальнаяЦена
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрСведений.ЦеныНоменклатуры.SrezPoslednih(&Период, Номенклатура В ИЕРАРХИИ(&Родитель)) КАК Цены
ПО
Номенклатура.Ссылка = Цены.Номенклатура
ГДЕ
Номенклатура.Ссылка В ИЕРАРХИИ(&Родитель)
И НЕ Номенклатура.ЭтоГруппа
Важный нюанс: условие В ИЕРАРХИИ в параметрах виртуальной таблицы заставляет платформу 1С ограничить выборку из регистра еще на этапе формирования SQL-запроса. Это критически важно для работы с большими базами данных.
Разберем ситуацию, когда для товара цена еще не была установлена. При использовании ЛЕВОГО СОЕДИНЕНИЯ в полях цены для таких строк вернется значение NULL. Чтобы ваш отчет или алгоритм не «сломался» при попытке математической операции, всегда используйте функцию ЕСТЬNULL(). Рассмотрим подробнее: функция принимает два аргумента — проверяемое поле и значение, которое нужно вернуть, если поле равно NULL (например, 0).
Если условие отбора номенклатуры очень сложное (например, зависит от нескольких свойств или остатков на складах), рекомендуется использовать методику временных таблиц. Разберем этот процесс по шагам:
ВТ_СписокНоменклатуры, куда помещаем только ссылки на нужные нам товары.ВТ_СписокНоменклатуры и СрезПоследних.СрезПоследних указываем фильтр: Номенклатура В (ВЫБРАТЬ Ссылка ИЗ ВТ_СписокНоменклатуры).Такой подход позволяет системе максимально эффективно использовать индексы таблиц и минимизировать объем передаваемых данных.
Посмотрим на параметр &Период. Если вы не передадите дату в виртуальную таблицу, 1С вернет срез на «самое текущее» время (на текущую секунду). Однако в запросах, работающих внутри документов или отчетов за прошлые периоды, крайне важно явно указывать дату. Например, &ДатаОтчета или КОНЕЦДНЯ(&ДатаДокумента), чтобы данные были консистентными и соответствовали моменту времени, за который формируется отчет.
Проанализируем структуру регистра цен. Если в регистре помимо Номенклатуры есть другие измерения (например, Характеристика или ВидЦены), а вы их не указали в фильтрах, запрос может вернуть несколько строк на одну позицию номенклатуры. Это приведет к «раздуванию» результата. Чтобы этого избежать, обязательно накладывайте фильтр по ВидуЦены в параметрах виртуальной таблицы:
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период,
Номенклатура В ИЕРАРХИИ(&Родитель) И ВидЦены = &НужныйВидЦены) КАК Цены
Для корректного и быстрого получения цен следуем трем правилам:
ЛЕВОЕ СОЕДИНЕНИЕ от таблицы справочника к таблице цен.(&Период, &Условие).ЕСТЬNULL.Соблюдение этих простых принципов позволит вам писать чистый, производительный и отказоустойчивый код в любых конфигурациях на базе 1С.