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

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

Разработчики 1С часто сталкиваются с ситуацией, когда один и тот же запрос выдает полные данные в консоли запросов, но при использовании в динамическом списке (ДС) некоторые колонки остаются пустыми. Это происходит потому, что динамический список — это не просто прямой запрос к базе данных, а сложный механизм, работающий на базе системы компоновки данных (СКД), который на лету модифицирует текст запроса для оптимизации производительности. Разберем по шагам, почему это происходит и как заставить данные отображаться корректно.

Агрессивная оптимизация запроса в СКД

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

Рассмотрим пример запроса, с которым возникла проблема:


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

Если в настройках формы колонка Статус не отображается или система считает ее избыточной, связь с таблицей Ограничения может быть отброшена. Чтобы этого избежать, мы можем программно указать системе, что поле критически важно для выборки. Для этого используем метод УстановитьОбязательноеИспользование:


// В процедуре ПриСозданииНаСервере
ЭлементСписка = Список.КомпоновщикНастроек.Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ЭлементСписка.Поле = Новый ПолеКомпоновкиДанных("Статус");
ЭлементСписка.Использование = Истина;

// Или более современный способ через свойства реквизита
Список.УстановитьОбязательноеИспользование("Статус", Истина);

Особенности цепочки левых соединений

Выясним причину, связанную с логикой построения связей. В приведенном выше запросе используется цепочка из двух левых соединений. Важно понимать: если во второй таблице (Ограничения) отсутствует запись, соответствующая складу из первой таблицы (ИсторияХ), то во всех полях таблицы Ограничения будет значение NULL.

Следовательно, условие связи со следующей таблицей Ограничения.СкладИсточник = СтатусыНоменклатурыСрезПоследних.Склад не сработает, так как Ограничения.СкладИсточник равен NULL. В итоге поле Статус также вернет NULL, даже если данные в регистре статусов существуют. Консоль запросов часто ведет себя более «предсказуемо» из-за отсутствия внешних фильтров, которые накладывает динамический список.

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

Влияние функциональных опций

Проанализируем ситуацию с функциональными опциями (ФО). Это одна из самых «невидимых» причин расхождения данных. В 1С динамический список автоматически учитывает настройки функциональных опций. Если поле Статус или весь регистр СтатусыНоменклатуры привязаны к функциональной опции, которая в данный момент выключена, платформа намеренно подставит NULL в это поле или вовсе скроет колонку.

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

Параметры виртуальных таблиц и автоматические отборы

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

Рекомендуется явно указывать параметры в скобках виртуальной таблицы, чтобы минимизировать произвол СКД:


// Вместо СтатусыНоменклатуры.СрезПоследних(&ТекДата, )
// Используйте фильтрацию внутри параметров
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.СтатусыНоменклатуры.СрезПоследних(&ТекДата, {(Склад).* КАК Склад}) КАК СтатусыНоменклатурыСрезПоследних

Использование фигурных скобок {} в тексте запроса позволяет динамическому списку корректно подставлять пользовательские отборы непосредственно в параметры виртуальной таблицы, что значительно повышает точность и скорость выполнения запроса.

Права доступа (RLS)

Несмотря на использование полных прав, стоит помнить об ограничениях на уровне записей (RLS). В некоторых случаях динамический список может запускаться в контексте, где накладываются дополнительные ограничения на чтение отдельных полей. В консоли запросов такие ограничения могут не проявляться, если она запущена в привилегированном режиме или под другим профилем безопасности. Убедитесь, что у пользователя (даже с административными правами) нет специфических запретов на чтение конкретных ресурсов регистра сведений.

Пользовательские настройки и кэширование

Иногда причина кроется в сохраненных настройках самого пользователя. Динамические списки кэшируют структуру колонок и примененные фильтры. Посмотрите в меню «Еще — Установить стандартные настройки». Если после изменения кода в конфигураторе данные все равно не появляются, велика вероятность, что система использует старый вариант компоновки из кэша. Попробуйте временно изменить имя реквизита динамического списка или очистить кэш метаданных информационной базы.

Подводя итог, для исправления ситуации следует выполнить следующие действия:

  1. Проверить цепочку соединений на наличие NULL в промежуточных таблицах.
  2. Явно указать обязательное использование полей через УстановитьОбязательноеИспользование.
  3. Проверить связь объектов с функциональными опциями.
  4. Оптимизировать параметры виртуальных таблиц с использованием расширения языка запросов (фигурные скобки).
  5. Сбросить пользовательские настройки формы до стандартных.
← На главную