Почему не отображаются данные в динамическом списке при использовании произвольного запроса с объединением и фильтрами?

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

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

Разбор исходной проблемы

Рассмотрим ситуацию. У нас есть запрос, который объединяет остатки из двух регистров: СвободныеОстатки и ТоварыВРезервеНаСкладах. В консоли запросов все данные выводятся корректно, но как только мы добавляем в параметры виртуальной таблицы условие по ответственному лицу (через разыменование поля), список перестает отображать даже те строки, которые не должны фильтроваться этим условием.

Исходный код запроса в динамическом списке:


ВЫБРАТЬ
    СвободныеОстаткиОстатки.Склад КАК Склад,
    СУММА(СвободныеОстаткиОстатки.КоличествоОстаток) КАК Количество,
    СвободныеОстаткиОстатки.СерияНоменклатуры КАК СерияНоменклатуры,
    NULL КАК ДокументРезерва
ИЗ
    РегистрНакопления.СвободныеОстатки.Остатки(, Номенклатура = &Номенклатура) КАК СвободныеОстаткиОстатки
СГРУППИРОВАТЬ ПО
    СвободныеОстаткиОстатки.Склад,
    СвободныеОстаткиОстатки.СерияНоменклатуры

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ТоварыВРезервеНаСкладахОстатки.Склад,
    СУММА(ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток),
    ТоварыВРезервеНаСкладахОстатки.СерияНоменклатуры,
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва
ИЗ
    РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки(
        ,
        Номенклатура = &Номенклатура
            И ДокументРезерва.Ответственный = &ТекущийПользователь) КАК ТоварыВРезервеНаСкладахОстатки
СГРУППИРОВАТЬ ПО
    ТоварыВРезервеНаСкладахОстатки.Склад,
    ТоварыВРезервеНаСкладахОстатки.СерияНоменклатуры,
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва

Выясним причины, по которым этот механизм может давать сбой в динамическом списке.

Причина 1: Разыменование полей через точку в параметрах виртуальных таблиц

Проанализируем конструкцию ДокументРезерва.Ответственный = &ТекущийПользователь внутри параметров виртуальной таблицы. В обычном запросе платформа 1С автоматически создает ЛЕВОЕ СОЕДИНЕНИЕ с таблицей документа, чтобы получить значение реквизита Ответственный.

Однако динамический список базируется на системе компоновки данных (СКД). Когда СКД генерирует итоговый SQL-запрос, она «оборачивает» ваш текст в подзапрос. Если поле ДокументРезерва имеет составной тип (например, несколько видов документов резервирования), разыменование через точку внутри параметров виртуальной таблицы может привести к тому, что оптимизатор запросов построит некорректный план или вовсе не сможет разрешить типы. В итоге результат всего объединения становится пустым.

Рекомендация: Выносите сложные фильтры из параметров виртуальной таблицы в общую секцию ГДЕ. Это позволит системе компоновки данных более гибко управлять соединениями.


ИЗ
    РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки(, Номенклатура = &Номенклатура) КАК ТоварыВРезервеНаСкладахОстатки
ГДЕ
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва.Ответственный = &ТекущийПользователь

Причина 2: Проблема типизации NULL в объединениях (UNION)

Посмотрим на первую часть запроса: NULL КАК ДокументРезерва. Динамический список крайне чувствителен к типам колонок. Если в одной части объединения стоит NULL, а в другой — ссылка на документ, платформа может определить тип колонки как «Неизвестный» или принудительно привести его к типу первой выборки.

Если тип колонки определен неверно, любые последующие отборы (в том числе и встроенные отборы ДС) по этой колонке или связанным полям будут работать непредсказуемо. Это объясняет, почему при добавлении фильтра во вторую часть запроса пропадают данные даже из первой, где этого фильтра нет.

Решение: Используйте конструкцию ВЫРАЗИТЬ или пустую ссылку конкретного типа для жесткого указания типа колонки.


// Вместо NULL КАК ДокументРезерва
ВЫРАЗИТЬ(NULL КАК Документ.ЗаказПокупателя) КАК ДокументРезерва
// Или, если типов много:
ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка) КАК ДокументРезерва

Причина 3: Установка параметров динамического списка

Проверим, как устанавливаются параметры в коде. Рассмотрим пример из процедуры ПриАктивизацииСтрокиНаСервере:


&НаСервере
Процедура НоменклатураПриАктивизацииСтрокиНаСервере(ВыбраннаяНоменклатура)
    ОстаткиПоСкладам.Параметры.УстановитьЗначениеПараметра("Номенклатура", ВыбраннаяНоменклатура);
    ОстаткиПоСкладам.Параметры.УстановитьЗначениеПараметра("ТекущийПользователь", ПараметрыСеанса.ТекущийПользователь);
КонецПроцедуры

Важно помнить, что если параметр ТекущийПользователь в схеме запроса динамического списка имеет определенный тип (например, СправочникСсылка.Пользователи), а в ПараметрыСеанса по какой-то причине значение не установлено или имеет тип Неопределено, динамический список не выдаст ошибку, он просто вернет пустой результат.

Также стоит убедиться, что свойство «Использовать всегда» для этих параметров в настройках динамического списка включено, либо они явно присутствуют в тексте запроса. Если динамический список решит оптимизировать запрос и «выкинуть» часть с параметром, данные могут отображаться некорректно.

Итоговый правильный вариант запроса

Соберем все рекомендации воедино. Проанализируем исправленный текст запроса, который будет стабильно работать в динамическом списке:


ВЫБРАТЬ
    СвободныеОстаткиОстатки.Склад КАК Склад,
    СвободныеОстаткиОстатки.КоличествоОстаток КАК Количество,
    СвободныеОстаткиОстатки.СерияНоменклатуры КАК СерияНоменклатуры,
    ЗНАЧЕНИЕ(Документ.ЗаказПокупателя.ПустаяСсылка) КАК ДокументРезерва
ИЗ
    РегистрНакопления.СвободныеОстатки.Остатки(&Период, Номенклатура = &Номенклатура) КАК СвободныеОстаткиОстатки

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ТоварыВРезервеНаСкладахОстатки.Склад,
    ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток,
    ТоварыВРезервеНаСкладахОстатки.СерияНоменклатуры,
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва
ИЗ
    РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки(&Период, Номенклатура = &Номенклатура) КАК ТоварыВРезервеНаСкладахОстатки
ГДЕ
    ТоварыВРезервеНаСкладахОстатки.ДокументРезерва.Ответственный = &ТекущийПользователь

Полезные советы для работы с ДС

  1. Проверяйте «Основную таблицу»: Для запросов с ОБЪЕДИНИТЬ основную таблицу выбрать невозможно. Убедитесь, что в настройках списка включено «Автозаполнение», чтобы система могла корректно определить ключевые поля. Без ключей динамический список часто не может отобразить данные или позиционироваться на них.
  2. Используйте ВЫРАЗИТЬ для составных типов: Если поле ДокументРезерва составное, обращение через точку к Ответственный заставляет систему делать соединения со всеми таблицами документов, входящих в состав. Это замедляет работу. Используйте ВЫРАЗИТЬ(ДокументРезерва КАК Документ.ЗаказПокупателя).Ответственный.
  3. Отладка через консоль СКД: Чтобы понять, какой именно запрос отправляет динамический список в СУБД, используйте специальные обработки — консоли компоновки данных. Обычная консоль запросов не учитывает «обертки», которые накладывает ДС.
  4. Права доступа (RLS): Помните, что динамический список всегда учитывает RLS. Если у пользователя нет прав на просмотр поля Ответственный в документах резерва, фильтр отсечет все записи, даже если в консоли под полными правами всё работает.

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

← На главную