При разработке отчетов и обработок на платформе 1С, особенно в рамках Системы Компоновки Данных (СКД), часто возникает необходимость сравнить значение какого-либо поля с конкретным элементом справочника. Эта задача может показаться нетривиальной, если речь идет не о предопределенном элементе, который легко получить с помощью конструкции Значение(Справочник.ИмяСправочника.ИмяПредопределенногоЭлемента). Мы с вами разберем, как эффективно и надежно обращаться к любым элементам справочников в запросах, даже если они не являются предопределенными, а также рассмотрим нюансы работы в СКД.
Давайте проанализируем ситуацию: нам нужно создать вычисляемое поле в запросе, где логика зависит от того, равен ли некий НужноеПоле конкретному элементу справочника. Например, наша задача выглядит так:
ВЫБОР КОГДА НужноеПоле = Справочник.НужныйСправочник.НужныйЭлемент ТОГДА Формула ИНАЧЕ ДругоеНужноеПоле
Такая прямая запись Справочник.НужныйСправочник.НужныйЭлемент возможна только для предопределенных элементов. Для любых других элементов справочника, которые пользователь может создавать, изменять или удалять, требуется другой подход.
Самый распространенный, гибкий и безопасный способ обращения к элементам справочника в запросе — это использование параметров. Мы передаем ссылку на нужный элемент в запрос из кода или из настроек СКД.
В тексте запроса вместо прямой ссылки на элемент мы указываем параметр, который начинается с символа амперсанда (&). Например, &НужныйЭлемент1.
ВЫБОР КОГДА НужноеПоле1 = &НужныйЭлемент1 ТОГДА Формула Иначе НужноеПоле2 КОНЕЦ
В этом примере НужноеПоле1 будет сравниваться со значением, которое мы передадим в параметр НужныйЭлемент1.
После того как текст запроса сформирован, но до его выполнения, нам необходимо присвоить значение нашему параметру &НужныйЭлемент1. Это делается программно с помощью метода Запрос.УстановитьПараметр().
Запрос.УстановитьПараметр("НужныйЭлемент1", Справочники.НужныйСправочник.НужныйЭлемент);
Здесь Справочники.НужныйСправочник.НужныйЭлемент — это реальная ссылка на конкретный элемент справочника. Давайте разберемся, как мы можем получить эту ссылку.
Существует несколько основных способов получить ссылку на конкретный элемент справочника, чтобы затем передать её в параметр запроса:
Из реквизита формы отчета или обработки:
Если вы разрабатываете отчет или обработку с формой, вы можете разместить на ней поле выбора справочника. Пользователь выбирает нужный элемент, а мы затем берем его значение и передаем в параметр.
// Предположим, на форме есть реквизит с именем "ЭлементСправочникаДляОтбора"
// с типом СправочникСсылка.НужныйСправочник
Если НЕ ЗначениеЗаполнено(ЭлементСправочникаДляОтбора) Тогда
Сообщить("Необходимо выбрать элемент справочника для отбора!");
Возврат;
КонецЕсли;
Запрос.УстановитьПараметр("НужныйЭлемент1", ЭлементСправочникаДляОтбора);
Этот подход наиболее удобен для пользователя, так как он сам определяет, какой элемент ему нужен.
Программный поиск элемента по коду или наименованию:
Если мы знаем код или наименование нужного элемента, мы можем найти его программно и получить ссылку. Для этого используются методы НайтиПоКоду() или НайтиПоНаименованию() соответствующего менеджера справочника.
// Поиск элемента по коду
ЗначениеЭлемента = Справочники.НужныйСправочник.НайтиПоКоду("00001");
// Важно: всегда проверяйте, найден ли элемент!
Если ЗначениеЭлемента = Неопределено Тогда
Сообщить("Элемент справочника с кодом '00001' не найден. Проверьте данные.");
Возврат;
КонецЕсли;
Запрос.УстановитьПараметр("НужныйЭлемент1", ЗначениеЭлемента);
// Или поиск по наименованию
// ЗначениеЭлемента = Справочники.НужныйСправочник.НайтиПоНаименованию("Мой любимый элемент");
// ...далее аналогичная проверка и установка параметра...
Важный момент: если элемент не будет найден, методы НайтиПоКоду() и НайтиПоНаименованию() вернут значение Неопределено. Передача Неопределено в параметр запроса может привести к ошибкам или некорректным результатам. Поэтому всегда следует проверять, что найденный элемент существует.
Прямая ссылка на предопределенный элемент (для сравнения):
Хотя наша задача — работа с непредопределенными элементами, для полноты картины упомянем, что для предопределенных элементов ссылка получается напрямую:
Запрос.УстановитьПараметр("НужныйЭлемент1", Значение(Справочник.НужныйСправочник.ИмяПредопределенногоЭлемента));
Когда мы работаем с отчетами на СКД, концепция параметров приобретает особое значение. СКД предоставляет мощные инструменты для управления данными, отборами и параметрами.
Создание параметра в СКД:
В схеме компоновки данных, на вкладке "Параметры", мы можем создать новый параметр. Дайте ему осмысленное имя (например, ПараметрОтборПоЭлементу) и укажите тип — СправочникСсылка.НужныйСправочник. Этот параметр затем можно использовать в условиях отбора или в тексте запроса набора данных, как мы это делали выше (&ПараметрОтборПоЭлементу).
Важно: убедитесь, что параметр правильно связан с полем отбора или с полем в запросе набора данных. Мы можем настроить пользовательские настройки для этого параметра, чтобы пользователи могли выбирать его на форме отчета.
Управление параметрами через форму отчета СКД:
Для удобства пользователя рекомендуется не жестко кодировать значения элементов в запросе СКД, а дать возможность пользователю выбирать нужный элемент на форме отчета. Это можно сделать, добавив в параметры СКД наш параметр типа СправочникСсылка.НужныйСправочник и сделав его доступным для редактирования пользователем.
Если вы столкнулись с проблемой, что НайтиПоКоду() или НайтиПоНаименованию() "не работают" в контексте СКД (как это было в одном из сообщений форума), это, скорее всего, означает, что вы пытаетесь использовать их непосредственно в запросе СКД, что невозможно. Эти методы являются методами менеджера справочника и вызываются из кода 1С (например, в модуле объекта отчета или в модуле менеджера). Внутри текста запроса СКД мы оперируем только данными, полученными из таблиц базы данных, и параметрами.
Программное получение значения параметра в СКД (в коде модуля отчета):
Если вам нужно программно получить или установить значение параметра СКД (например, в процедуре ПриКомпоновкеРезультата или ПриСозданииНаСервере), вы можете обратиться к объекту КомпоновщикНастроек.Настройки.ПараметрыДанных и найти нужный параметр по имени:
// Пример в модуле отчета
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартную обработку, если хотим управлять выводом
СтандартнаяОбработка = Ложь;
// Получаем компоновщик настроек
КомпоновщикНастроек.Восстановить();
// Находим наш параметр по имени
Параметр = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра("НужныйЭлемент1");
Если Параметр <> Неопределено Тогда
// Проверяем, задано ли значение пользователем
Если Параметр.ЗначениеЗаполнено И Параметр.Использование Тогда
// Получаем значение, заданное пользователем
ЗначениеЭлементаОтбора = Параметр.Значение;
// ...далее используем ЗначениеЭлементаОтбора в своей логике
Сообщить("Для отбора используется элемент: " + ЗначениеЭлементаОтбора);
Иначе
Сообщить("Параметр 'НужныйЭлемент1' не задан или не используется.");
КонецЕсли;
КонецЕсли;
// ...Дальнейшая логика компоновки или вызова стандартного формирования
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
В некоторых ситуациях, если вы абсолютно уверены в стабильности кодов или наименований элементов справочника, можно сравнивать поля по этим строковым представлениям. Однако этот метод считается менее надежным, чем сравнение по ссылке, поскольку код или наименование могут быть изменены пользователем, что приведет к некорректной работе запроса. Для решения задач, где требуется сопоставление строковых представлений со ссылками, можно использовать руководство по сравнению строк со ссылками в запросах 1С.
Пример такого сравнения в запросе:
ВЫБОР КОГДА НужноеПоле1.Код = "ИскомыйКод" ТОГДА Формула Иначе НужноеПоле2 КОНЕЦ
Здесь НужноеПоле1 — это ссылочное поле (например, Номенклатура или Контрагент), и мы обращаемся к его реквизиту Код. Аналогично можно сравнивать и по Наименованию (НужноеПоле1.Наименование = "ИскомоеНаименование").
Недостатки этого метода:
Мы рекомендуем использовать этот метод только в крайних случаях и при очень строгих гарантиях того, что коды или наименования не будут меняться и всегда будут уникальны.
Для более глубокого понимания работы со ссылочными типами данных в 1С, рассмотрим несколько ключевых моментов:
Что такое ссылка в 1С?
Ссылка на объект (например, элемент справочника, документ, элемент плана видов характеристик) является его уникальным внутренним идентификатором в базе данных. Она представляет собой набор символов (UUID/GUID) и является самым надежным способом идентификации объекта. При сравнении по ссылке мы сравниваем именно эти уникальные идентификаторы, а не их внешние представления (наименования, коды).
Все ссылки объектов имеют определенный тип, например, СправочникСсылка.НазваниеСправочника, ДокументСсылка.НазваниеДокумента и т.д.
Работа с пустыми ссылками:
Часто возникает необходимость проверить, заполнена ли ссылочная переменная или поле. Для сравнения с пустой ссылкой используется специальная функция:
// В запросе
ВЫБОР КОГДА НужноеПоле = ЗНАЧЕНИЕ(Справочник.НужныйСправочник.ПустаяСсылка) ТОГДА "Поле пустое" ИНАЧЕ "Поле заполнено" КОНЕЦ
// В коде 1С
Если НужноеПоле = Справочники.НужныйСправочник.ПустаяСсылка Тогда
Сообщить("Поле не заполнено.");
КонецЕсли;
Оператор ССЫЛКА в запросе:
Этот оператор полезен, когда нам нужно проверить, является ли значение поля ссылкой на определенную таблицу (тип объекта). Это особенно актуально для полей составного типа.
// Пример: выбрать все записи, где поле "Владелец" является ссылкой на справочник "Контрагенты"
ВЫБРАТЬ
Таблица.Поле1,
Таблица.Владелец
ИЗ
КакойТоТаблица КАК Таблица
ГДЕ
Таблица.Владелец ССЫЛКА Справочник.Контрагенты
Функция ВЫРАЗИТЬ() для составных типов:
Если ваше поле может иметь составной тип (т.е. оно может содержать ссылки на разные справочники или документы), и вам нужно сравнить его с элементом конкретного типа, используйте функцию ВЫРАЗИТЬ(). Она позволяет "привести" значение поля к определенному типу для корректного сравнения или доступа к реквизитам.
// Пример: в поле "ОбъектРасчетов" может быть и Номенклатура, и Услуга.
// Нам нужно сравнить только те записи, где это Номенклатура, с конкретной позицией.
ВЫБОР КОГДА ВЫРАЗИТЬ(ПолеССоставнымТипом КАК Справочник.Номенклатура) = &НужнаяНоменклатура ТОГДА "Номенклатура" ИНАЧЕ "Другое" КОНЕЦ
Без ВЫРАЗИТЬ() сравнение ПолеССоставнымТипом = &НужнаяНоменклатура будет работать, но может быть менее эффективным, а при попытке обратиться к реквизитам типа (например, ПолеССоставнымТипом.Код) без явного приведения типа, запрос может завершиться ошибкой, если значение поля не соответствует типу, к реквизиту которого мы обращаемся.
Мы рассмотрели основные подходы к работе с элементами справочника в запросах 1С, особенно акцентируя внимание на не предопределенных элементах и особенностях СКД. Использование параметров запроса является наиболее предпочтительным и гибким методом, позволяющим создавать надежные и производительные решения. Всегда старайтесь использовать сравнение по ссылке и помните о важности проверки наличия найденных элементов.