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