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

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

При разработке отчетов, обработок и форм списков в 1С часто возникает задача вывести значения нескольких дополнительных реквизитов объекта в одной строке. В типовых конфигурациях (таких как 1С:Управление торговлей, 1С:ERP, 1С:Комплексная автоматизация) дополнительные реквизиты хранятся вертикально — в виде строк табличной части ДополнительныеРеквизиты или записей регистра сведений (пара «Свойство — Значение»).

Если написать простое условие с конструкцией ВЫБОР КОГДА без правильной группировки или соединения, строки документа будут дублироваться на каждое заполненное свойство. Проанализируем несколько способов решения этой задачи и разберем особенности их применения, в том числе для динамических списков.

Способ 1. Использование нескольких левых соединений

Классический и наиболее прямолинейный подход — выбрать документы из основной таблицы и последовательно присоединить к ним табличную часть дополнительных реквизитов с фильтрацией по конкретному свойству в условии соединения.

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


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

Особенности способа:

  1. Условие по свойству обязательно должно находиться в секции ПО (в условии соединения), а не в секции ГДЕ, иначе левое соединение превратится во внутреннее, и документы с незаполненными реквизитами пропадут из выборки.
  2. Функция ЕСТЬNULL позволяет заменить пустые значения NULL на пустую строку или значение по умолчанию.
  3. Этот способ хорошо подходит, если требуется вывести 2–3 фиксированных реквизита. Если реквизитов много (10 и более), большое количество соединений может снизить производительность выполнения запроса СУБД.

Способ 2. Группировка с агрегатной функцией (в один проход)

Чтобы избежать множественных соединений одной и той же таблицы, можно прочитать таблицу дополнительных реквизитов один раз и свернуть строки в колонки с помощью группировки и агрегатной функции МАКСИМУМ.

Разберем структуру такого запроса:


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

Преимущества метода:

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

Способ 3. Пакетный запрос с временными таблицами

В сложных отчетах и пакетных алгоритмах удобно разделять выборку каждого реквизита во временные таблицы (МенеджерВременныхТаблиц) с последующим объединением.

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


ВЫБРАТЬ
	ДопРекв.Ссылка КАК Ссылка,
	ДопРекв.Значение КАК ВремяСборки
ПОМЕСТИТЬ ВТ_ВремяСборки
ИЗ
	Документ.ЗаказКлиента.ДополнительныеРеквизиты КАК ДопРекв
ГДЕ
	ДопРекв.Свойство = &СвойствоВремяСборки
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ДопРекв.Ссылка КАК Ссылка,
	ДопРекв.Значение КАК Курьер
ПОМЕСТИТЬ ВТ_Курьеры
ИЗ
	Документ.ЗаказКлиента.ДополнительныеРеквизиты КАК ДопРекв
ГДЕ
	ДопРекв.Свойство = &СвойствоКурьер
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Заказ.Ссылка КАК Ссылка,
	ЕСТЬNULL(ВТ_ВремяСборки.ВремяСборки, "") КАК ВремяСборки,
	ЕСТЬNULL(ВТ_Курьеры.Курьер, "") КАК Курьер
ИЗ
	Документ.ЗаказКлиента КАК Заказ
	ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ВремяСборки КАК ВТ_ВремяСборки
		ПО Заказ.Ссылка = ВТ_ВремяСборки.Ссылка
	ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Курьеры КАК ВТ_Курьеры
		ПО Заказ.Ссылка = ВТ_Курьеры.Ссылка

Особенности вывода дополнительных реквизитов в динамических списках

Если задача состоит в отображении колонок дополнительных реквизитов в форме списка документов, необходимо учитывать ограничения платформы 1С:

  1. Динамическое считывание данных: Использование в тексте запроса динамического списка конструкций СГРУППИРОВАТЬ ПО, ОБЪЕДИНИТЬ или сложных подзапросов может привести к отключению порционной загрузки данных. В этом случае сервер будет считывать весь список документов целиком, что приведет к зависанию формы при открытии.
  2. Основная таблица: Для сохранения высокой скорости работы, возможности поиска и установки пользовательских отборов у динамического списка обязательно должно быть заполнено свойство ОсновнаяТаблица (например, Документ.ЗаказКлиента).
  3. Оптимальный способ для динамического списка: При небольшом числе дополнительных реквизитов (1–3) в запросе списка рекомендуется использовать простые левые соединения (Способ 1).
  4. Вывод через событие «ПриПолученииДанныхНаСервере»: Если реквизитов много, чтобы не перегружать запрос списка, в таблицу формы добавляют строковые колонки без пути к данным, а их значения заполняют в серверном событии ПриПолученииДанныхНаСервере. В этом обработчике одним запросом по массиву ссылок только видимой на экране порции строк выбираются значения свойств и подставляются в оформление ячеек.
← На главную