Почему не работает сравнение дат в СКД и как правильно настроить отбор в виртуальных таблицах?

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

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

Причина 1: Магия зарезервированного параметра &Период

Первое, на что мы должны обратить внимание, — это имя параметра. В СКД имя &Период является системным и зарезервированным. Когда система видит этот параметр, она включает механизмы автоматической обработки. Если вы используете его в виртуальных таблицах, таких как СрезПоследних или Остатки, СКД связывает его с датой получения данных.

Проблема возникает, когда мы пытаемся использовать &Период одновременно и как дату получения остатков/среза, и как значение для фильтрации в секции ГДЕ или в параметрах отбора виртуальной таблицы. В этом случае компоновщик может подставить туда объект Граница или специфическое значение начала дня, которое не пройдет проверку на равенство с обычной датой типа Дата. Проанализируем решение этой проблемы:

  1. Перейдем на закладку Параметры в схеме компоновки данных.
  2. Создадим новый параметр с уникальным именем, например &ДатаОтбора или &НужнаяДата.
  3. Установим ему тип Дата.
  4. В тексте запроса заменим использование &Период на наше новое имя.

Рассмотрим пример того, как это должно выглядеть в коде запроса:


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

Причина 2: Логическое противоречие в СрезеПоследних

Разберем ситуацию, когда отбор накладывается внутри параметров виртуальной таблицы СрезПоследних. Часто разработчики пишут условие вида Период >= &Период внутри скобок виртуальной таблицы. Это классическая логическая ловушка.

Выясним причину: первый параметр виртуальной таблицы (момент времени) указывает системе, на какую дату нужно искать последнюю запись. Это значит, что система ищет записи, чья дата меньше или равна указанной. Если вы тут же добавляете фильтр Период >= &Период, вы ограничиваете выборку записями, которые были созданы после или в ту же секунду, что и дата среза. В итоге результат будет получен только в том случае, если есть запись с точностью до секунды совпадающая с параметром. Во всех остальных случаях отчет будет пустым.

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

Причина 3: Использование полей через точку от Регистратора

Проанализируем еще одну частую ошибку — обращение к реквизитам через поле Регистратор внутри параметров виртуальной таблицы. В примере из темы форума мы видим конструкцию:

СрезПоследних(&Период, ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.ПеремещениеНоменклатуры) И Регистратор.Проведен = ИСТИНА)

Такой подход крайне неэффективен и может приводить к сбоям в СКД. Посмотрим, как оптимизировать этот запрос:

Пример оптимизированного подзапроса:


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

Особенности работы с UNION ALL в СКД

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

Обратите внимание на поле ДатаВыхода или ДатаВхода в примере. Если в одной части объединения это число 0, а в другой — Дата, СКД может попытаться привести типы не тем способом, который вы ожидаете. Используйте пустые значения дат вместо нулей для типизации колонок:

ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) КАК ДатаВыхода

Итоговые рекомендации

Подведем итог. Чтобы сравнение дат в СКД всегда работало предсказуемо, следуйте этим правилам:

  1. Не используйте &Период для фильтрации: оставьте этот параметр только для виртуальных таблиц как дату получения данных. Для пользовательских отборов по дате создайте свой параметр с понятным именем.
  2. Проверяйте настройки параметров: на закладке "Параметры" убедитесь, что у вашего параметра явно задан тип Дата и не стоит ограничение доступности, если пользователь должен его заполнять.
  3. Выносите условия из виртуальных таблиц: если фильтрация сложная (использует Регистратор, ВЫБОР или сравнение нескольких дат), лучше наложить ее в секции ГДЕ после получения данных из регистра.
  4. Используйте ССЫЛКА и ВЫРАЗИТЬ: это поможет избежать неявных левых соединений со всеми таблицами документов-регистраторов и повысит производительность отчета.

Применяя эти методы, вы избавитесь от "мистических" исчезновений данных из отчета и сделаете свои запросы более устойчивыми к изменениям платформы 1С.

← На главную