При разработке интерфейсов на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью вывода сложных данных в списках. Одной из распространенных задач является отображение информации из регистров накопления или сведений непосредственно в списке справочника. Для этого в динамическом списке (ДС) используется произвольный запрос с левым соединением. Однако такая структура может привести к неожиданным ошибкам при попытке стандартного поиска по списку. Рассмотрим, почему это происходит и как правильно настроить систему для корректной работы.
Типичный сценарий: в динамическом списке справочника необходимо вывести остаток товара или ответственного сотрудника, данные о которых хранятся в регистре. Чтобы избежать дублирования строк (когда одному объекту справочника соответствует несколько записей в регистре), разработчики прибегают к группировке СГРУППИРОВАТЬ ПО и использованию агрегатных функций, таких как МАКСИМУМ или СУММА.
Проблема проявляется в тот момент, когда пользователь вводит текст в строку поиска. Платформа генерирует внутренний SQL-запрос, пытаясь найти совпадение во всех доступных колонках. Если колонка является ссылочной (например, тип Справочник.Сотрудники), 1С автоматически пытается выполнить поиск по представлению этой ссылки — то есть по полю Наименование.
Однако, если поле получено в результате работы функции МАКСИМУМ(Сотрудник), оно перестает быть простой ссылкой в глазах механизма поиска. Система пытается обратиться к атрибуту Наименование у результата агрегации, что вызывает технический сбой, так как СУБД не может корректно обработать такое обращение в конструкции WHERE или HAVING без дополнительных инструкций.
Проанализируем пример запроса, который вызывает ошибку. В данном случае разработчик пытается получить данные об ИТ-объектах и привязать к ним сотрудника из регистра накопления:
ВЫБРАТЬ
СправочникАА_ИТОбъекты.Ссылка КАК Ссылка,
СправочникАА_ИТОбъекты.Код КАК Код,
СправочникАА_ИТОбъекты.Наименование КАК Наименование,
ВЫРАЗИТЬ(СправочникАА_ИТОбъекты.Описание КАК СТРОКА(250)) КАК Описание,
СУММА(АА_ИТОбъектыИСотрудникиОстатки2.КоличествоОстаток) КАК ВсегоОстаток,
МАКСИМУМ(ЕСТЬNULL(АА_ИТОбъектыИСотрудникиОстатки2.Сотрудник, ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка))) КАК Сотрудник
ИЗ
Справочник.АА_ИТОбъекты КАК СправочникАА_ИТОбъекты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.АА_ИТОбъектыИСотрудники.Остатки КАК АА_ИТОбъектыИСотрудникиОстатки2
ПО АА_ИТОбъектыИСотрудникиОстатки2.ИТОбъект = СправочникАА_ИТОбъекты.Ссылка
СГРУППИРОВАТЬ ПО
СправочникАА_ИТОбъекты.Ссылка,
СправочникАА_ИТОбъекты.Код,
СправочникАА_ИТОбъекты.Наименование
Обратим внимание на поле Сотрудник. Здесь используется связка МАКСИМУМ и ЕСТЬNULL. Именно эта конструкция становится «камнем преткновения» для стандартного поиска. Платформа «видит» тип данных как ссылку, но при попытке поиска по строке не может корректно сопоставить агрегированное значение с полем Наименование в таблице сотрудников.
Самый быстрый способ устранить ошибку, не меняя структуру запроса — это подсказать системе, как работать с данным полем. В настройках динамического списка (закладка «Настройки компоновки данных» в окне редактирования запроса) необходимо выполнить следующие действия:
Сотрудник.Установка этих флагов сообщает платформе, что по данному полю (которое является результатом агрегации) не следует выполнять автоматическую фильтрацию или поиск. Это исключает генерацию некорректного SQL-кода, и ошибка пропадает. Пользователь сможет искать по наименованию объекта или коду, а проблемная колонка будет игнорироваться механизмом поиска.
Использование СГРУППИРОВАТЬ ПО в основном тексте динамического списка — не самая лучшая практика с точки зрения производительности. Платформа при наложении пользовательских отборов вынуждена оборачивать такой запрос во вложенные конструкции, что замедляет работу системы.
Рассмотрим более правильный подход — вынесение логики получения единственного сотрудника во вложенный запрос. Это позволит полю Сотрудник оставаться «чистым» ссылочным полем в основном запросе.
Проанализируем пример оптимизированного запроса:
ВЫБРАТЬ
СправочникАА_ИТОбъекты.Ссылка КАК Ссылка,
СправочникАА_ИТОбъекты.Наименование КАК Наименование,
ПодзапросРегистра.Сотрудник КАК Сотрудник,
ПодзапросРегистра.ВсегоОстаток КАК ВсегоОстаток
ИЗ
Справочник.АА_ИТОбъекты КАК СправочникАА_ИТОбъекты
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
АА_ИТОбъектыИСотрудникиОстатки.ИТОбъект КАК ИТОбъект,
СУММА(АА_ИТОбъектыИСотрудникиОстатки.КоличествоОстаток) КАК ВсегоОстаток,
МАКСИМУМ(АА_ИТОбъектыИСотрудникиОстатки.Сотрудник) КАК Сотрудник
ИЗ
РегистрНакопления.АА_ИТОбъектыИСотрудники.Остатки КАК АА_ИТОбъектыИСотрудникиОстатки
СГРУППИРОВАТЬ ПО
АА_ИТОбъектыИСотрудникиОстатки.ИТОбъект
) КАК ПодзапросРегистра
ПО ПодзапросРегистра.ИТОбъект = СправочникАА_ИТОбъекты.Ссылка
В такой структуре поле Сотрудник на верхнем уровне запроса воспринимается платформой более предсказуемо. Однако даже в этом случае, если ошибка поиска сохраняется, следует воспользоваться настройками ролей полей в СКД.
Выясним еще одну важную деталь: динамический список требует уникальности ключа (обычно это поле Ссылка). Если из-за соединений в списке появляются дубли по ссылке, система выдаст ошибку «Обнаружены дублирующиеся ключи».
Именно для борьбы с этим в исходном примере и использовалась группировка. При использовании вложенных запросов или сложных соединений важно убедиться в следующем:
Ссылка установлена роль «Без дублей».Разберем ситуацию, если в списке включен режим Полнотекстовый поиск. Ошибка может возникать из-за того, что данные в регистре не индексируются механизмом полнотекстового поиска так же, как данные справочника. Когда система пытается найти строку «Иванов», она ищет ее в индексе. Но поле МАКСИМУМ(Сотрудник) отсутствует в индексе как строковое значение.
В этом случае платформа пытается переключиться на поиск через оператор ПОДОБНО, что в сочетании с GROUP BY приводит к существенному падению производительности или ошибке тайм-аута на больших таблицах. Поэтому ограничение условий поиска для агрегатных полей — это не просто способ убрать ошибку, но и метод оптимизации скорости работы формы.
Для исправления ошибки при поиске в динамическом списке выполним следующие шаги:
СУММА, МАКСИМУМ, МИНИМУМ) над ссылочными полями.Эти действия позволят сохранить функциональность поиска по основным реквизитам справочника и обеспечат стабильную работу формы без вылетов и технических сообщений.