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