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