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