Как выбрать данные из среза последних регистра сведений с приоритетом по единице измерения в 1С?

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

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

Разберем основные варианты решения этой задачи с помощью языка запросов 1С.

Способ 1. Соединение таблиц срезов с использованием функции ЕСТЬNULL

Выясним причину, почему простой срез последних с отбором в секции ГДЕ не подходит для такой задачи. Если наложить условие ЕдиницаИзмерения = &Тонна в секции ГДЕ, то записи с другими единицами измерения отсекутся полностью. Если же наложить условие в параметрах виртуальной таблицы, срез рассчитается только по «тоннам», и номенклатура, по которой были движения только в «кг», вообще не попадет в выборку.

Чтобы решить проблему, сформируем два среза и соединим их между собой. Первым срезом получим последние записи с отбором по приоритетной единице измерения («тонна»), а вторым — общий срез последних по всем единицам измерения.

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


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

Проанализируем работу этого запроса:

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

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

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

Разберем этот вариант:


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

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

Способ 3. Использование временной таблицы с вычисляемым приоритетом

Если ЕдиницаИзмерения в регистре сведений является реквизитом или ресурсом (а не измерением), наложение условия на нее в параметрах виртуальной таблицы СрезПоследних заставит СУБД считывать всю таблицу регистра, что негативно скажется на производительности. Для больших объемов данных рекомендуется подход с временной таблицей и приоритетами.

Рассмотрим реализацию по шагам:


// Пакет 1: Выборка записей с присвоением приоритета
ВЫБРАТЬ
	Т.Номенклатура КАК Номенклатура,
	Т.Период КАК Период,
	Т.Значение КАК Значение,
	ВЫБОР
		КОГДА Т.ЕдиницаИзмерения = &Тонна ТОГДА 1
		ИНАЧЕ 2
	КОНЕЦ КАК Приоритет
ПОМЕСТИТЬ ВТ_Записи
ИЗ
	РегистрСведений.ЦеныНоменклатуры КАК Т
ГДЕ
	Т.Период <= &Период;

// Пакет 2: Определение наивысшего приоритета для каждой номенклатуры
ВЫБРАТЬ
	Т.Номенклатура КАК Номенклатура,
	МИНИМУМ(Т.Приоритет) КАК МинПриоритет
ПОМЕСТИТЬ ВТ_Приоритеты
ИЗ
	ВТ_Записи КАК Т
СГРУППИРОВАТЬ ПО
	Т.Номенклатура;

// Пакет 3: Выборка итоговых данных
ВЫБРАТЬ
	Записи.Номенклатура КАК Номенклатура,
	Записи.Значение КАК Значение
ИЗ
	ВТ_Приоритеты КАК Приоритеты
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Записи КАК Записи
		ПО Приоритеты.Номенклатура = Записи.Номенклатура
		И Приоритеты.МинПриоритет = Записи.Приоритет

Важные особенности и нюансы работы

При построении запросов к виртуальным таблицам регистра сведений учитывайте следующие моменты:

← На главную