Как работать с произвольными запросами в динамических списках 1С и исправлять ошибки при использовании пакетов?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Динамический список — это мощный инструмент платформы 1С:Предприятие 8, позволяющий эффективно отображать большие объемы данных. Однако при переходе к использованию произвольных запросов разработчики часто сталкиваются с неочевидными ограничениями: отказом системы работать с пакетными запросами, ошибками при поиске полей и сложностями в динамическом изменении структуры колонок. В этой статье мы подробно разберем, как обойти эти ограничения, правильно настроить запрос и программно управлять составом данных в списке.

Проблема пакетных запросов и ошибка «Поле Active не найдено»

Рассмотрим ситуацию, когда при попытке использовать пакетный запрос (с временными таблицами) в динамическом списке система выдает ошибку вида «Поле Active не найдено» (или аналогичную по системным полям). Выясним причину этого поведения.

Исторически в платформе «1С:Предприятие 8.2» и ранних версиях 8.3 использование пакетных запросов в динамических списках было официально ограничено. Платформа ожидает, что результатом запроса будет единая выборка, к которой она сможет «приклеить» свои системные механизмы: постраничную навигацию, отборы и сортировку. Когда в тексте появляется пакет (несколько запросов, разделенных символом «;»), внутренний генератор запросов 1С теряет контекст основной таблицы.

Проанализируем основные способы решения этой проблемы:

  1. Использование вложенных запросов. Это самый надежный способ для старых версий платформы. Вместо того чтобы выгружать данные во временную таблицу в первом запросе пакета, оберните этот запрос во вложенный. Рассмотрим пример:

// Вместо пакета: 
// ВЫБРАТЬ Ссылка ИЗ Справочник.Номенклатура ПОМЕСТИТЬ ВТ_Данные; 
// ВЫБРАТЬ * ИЗ ВТ_Данные...

// Используем вложенный запрос:
ВЫБРАТЬ
    ВложенныйЗапрос.Ссылка,
    ВложенныйЗапрос.Код
ИЗ
    (ВЫБРАТЬ Ссылка, Код ИЗ Справочник.Номенклатура) КАК ВложенныйЗапрос

Переделка запроса на вложенный полностью устраняет ошибку ненайденных системных полей, так как структура запроса остается линейной.

  1. Переход на современные релизы платформы. Начиная с версии 8.3.10, платформа официально поддерживает временные таблицы в динамических списках. Однако важно помнить: последним запросом в пакете должен быть запрос, возвращающий результат (выборка), а не уничтожение временной таблицы.

Важность настройки «Основной таблицы»

При использовании произвольного запроса, особенно сложного, платформа не всегда может автоматически определить, данные какого объекта являются ключевыми. Если вы соединяете несколько таблиц, обязательно укажите свойство «Основная таблица» в настройках динамического списка в конфигураторе.

Зачем это нужно? Без основной таблицы динамический список лишается большинства своих преимуществ:

Как программно изменить запрос и добавить колонки

Иногда требуется изменить текст запроса во время работы программы, например, добавить выборку из другого регистра в зависимости от настроек пользователя. Рассмотрим, как это сделать правильно. Просто изменить свойство ТекстЗапроса недостаточно — колонки на форме сами не появятся.

Разберем алгоритм действий:

  1. Изменяем текст запроса объекта ДинамическийСписок.
  2. Программно добавляем элемент формы (колонку), если ее не было в конфигураторе.

Посмотрим на пример кода:


&НаСервере
Процедура ИзменитьСписокНаСервере()
    
    // 1. Меняем текст запроса
    НовыйТекст = "ВЫБРАТЬ Таблица.Ссылка, Таблица.Код, Таблица.НовоеПоле ИЗ Справочник.Номенклатура КАК Таблица";
    Список.ТекстЗапроса = НовыйТекст;
    
    // 2. Проверяем, есть ли уже такая колонка на форме
    Если Элементы.Найти("СписокНовоеПоле") = Неопределено Тогда
        // Добавляем новый элемент формы
        НоваяКолонка = Элементы.Добавить("СписокНовоеПоле", Тип("ПолеФормы"), Элементы.Список);
        НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
        // Указываем путь к данным: ИмяСписка.ИмяПоляВЗапросе
        НоваяКолонка.ПутьКДанным = "Список.НовоеПоле";
        НоваяКолонка.Заголовок = "Дополнительная колонка";
    КонецЕсли;
    
КонецПроцедуры

Важный нюанс: Если вы используете СКД внутри динамического списка, помните, что новые поля должны быть также добавлены в Список.КомпоновщикНастроек.Настройки.ВыбранныеПоля, иначе они могут не попасть в итоговую выборку.

Ограничения по параметрам запроса

Часто возникает желание передать в динамический список готовую таблицу значений в качестве параметра. Проанализируем, почему это невозможно. Динамический список — это клиент-серверный механизм, который генерирует SQL-запрос непосредственно к базе данных. Таблица значений — это объект, живущий в оперативной памяти сервера 1С. SQL-сервер ничего не знает о вашей ТЗ.

Как передать данные? Если вам нужно ограничить список набором значений из ТЗ, используйте массивы:


МассивСсылок = ТаблицаЗначений.ВыгрузитьКолонку("Ссылка");
Список.Параметры.УстановитьЗначениеПараметра("МассивСсылок", МассивСсылок);
// В запросе списка должно быть: ГДЕ Ссылка В (&МассивСсылок)

Механизм характеристик и отладка

Работа с характеристиками в динамических списках часто вызывала ошибки вплоть до релиза 8.3.15. Если вы используете механизм дополнительных реквизитов и сведений, убедитесь, что характеристики настроены в метаданных основной таблицы. В современных версиях платформы они подхватываются автоматически, если в запросе выбрана основная таблица.

Для отладки сложных запросов рекомендуется использовать специализированные консоли динамических списков. В отличие от обычных консолей запросов, они позволяют увидеть не только ваш исходный текст, но и финальный SQL-запрос, который платформа отправляет на сервер базы данных. Это помогает понять, почему список «тормозит» или почему возникают ошибки при наложении пользовательских фильтров.

Помните, что использование ОБЪЕДИНИТЬ (UNION) в произвольном запросе динамического списка может блокировать возможность динамического считывания, что негативно скажется на производительности при больших объемах данных. Всегда старайтесь оптимизировать запрос так, чтобы он оставался максимально простым для парсера платформы.

← На главную