При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда "умные" алгоритмы платформы пытаются оптимизировать запрос, добавляя условия отбора туда, где они логически не нужны. Особенно остро эта проблема проявляется в запросах с объединениями (ОБЪЕДИНИТЬ ВСЕ) и при использовании виртуальных таблиц, таких как СрезПоследних или Обороты. Разберем подробно, почему это происходит и как заставить СКД работать строго по нашему сценарию.
Рассмотрим ситуацию, когда в запросе есть две ветки объединения. В первой ветке мы хотим предоставить пользователю возможность фильтровать данные по Виду цены, а во второй ветке — жестко зашить конкретные предопределенные виды цен. Однако СКД видит, что в обеих частях UNION фигурирует поле с одним и тем же смысловым значением, и при наложении пользователем отбора "проталкивает" его (Filter Push-down) во все части запроса, включая те, где этот отбор нарушает логику получения данных.
Проанализируем типичный пример проблемного запроса:
ВЫБРАТЬ
Цены.Номенклатура,
Цены.ВидЦены,
Цены.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, {(ВидЦены)}) КАК Цены
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ЦеныСпец.Номенклатура,
ЦеныСпец.ВидЦены,
ЦеныСпец.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ЦенаСпец) КАК ЦеныСпец
Даже если мы не указали фигурные скобки {} во второй части запроса, СКД при включенном автозаполнении может добавить условие И ВидЦены В (&П) во вторую виртуальную таблицу, если пользователь установил отбор по виду цены в настройках отчета. Это происходит из-за того, что имена полей в итоговой выборке совпадают.
Самый надежный, но требующий внимательности метод — отключение флажка Автозаполнение на закладке "Наборы данных". Выясним, как это работает:
Когда автозаполнение выключено, компоновщик перестает "додумывать" за разработчика и использует только те конструкции в фигурных скобках, которые прописаны явно. Рассмотрим пример корректного описания параметров виртуальной таблицы:
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, { (Номенклатура).* КАК Номенклатура, (ВидЦены).* КАК ВидЦены } )
Если мы не хотим полностью отключать автозаполнение, можно "обмануть" механизм сопоставления полей. СКД связывает отборы по именам полей. Если во второй ветке запроса мы дадим полю ВидЦены другое имя, автоматический отбор к нему не применится. Проанализируем реализацию этого метода:
ВЫБРАТЬ
Т.Номенклатура КАК Номенклатура,
Т.ВидЦены КАК ВидЦены, -- Основное поле для отбора
Т.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, {(ВидЦены)}) КАК Т
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т.Номенклатура,
Т.ВидЦены КАК ВидЦены_Служебный, -- Псевдоним отличается, отбор не "приклеится"
Т.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &Цена1) КАК Т
Чтобы в итоговом отчете данные все равно выводились в одну колонку, на закладке Наборы данных в колонке Поле нужно оставить технические имена (ВидЦены и ВидЦены_Служебный), а в колонке Путь к данным для обоих полей указать одинаковое имя (например, ВидЦены). Однако этот метод может быть нестабилен, поэтому лучше использовать явное переименование с отключением доступности поля для условий.
Для сложных отчетов наиболее чистым решением является использование временных таблиц. Это позволяет полностью изолировать логику получения данных от финальной сборки результата. Посмотрим на пример кода:
// В первой временной таблице получаем данные с пользовательским отбором
ВЫБРАТЬ
Цены.Номенклатура,
Цены.ВидЦены,
Цены.Цена
ПОМЕСТИТЬ ВТ_ПользовательскиеЦены
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаЦен, {(Номенклатура), (ВидЦены)}) КАК Цены
;
// Во второй временной таблице получаем данные по фиксированным условиям
ВЫБРАТЬ
ЦеныСпец.Номенклатура,
ЦеныСпец.ВидЦены КАК ВидЦеныСпец,
ЦеныСпец.Цена
ПОМЕСТИТЬ ВТ_ФиксированныеЦены
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаЦен, ВидЦены В (&СписокЦен) {(Номенклатура)}) КАК ЦеныСпец
;
// Собираем результат
ВЫБРАТЬ
Т.Номенклатура,
Т.ВидЦены,
Т.Цена
ИЗ ВТ_ПользовательскиеЦены КАК Т
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т.Номенклатура,
Т.ВидЦеныСпец,
Т.Цена
ИЗ ВТ_ФиксированныеЦены КАК Т
В данном примере для второй таблицы мы намеренно не указываем ВидЦены в фигурных скобках расширения параметров. Благодаря тому, что данные сначала помещаются во временную таблицу, СКД сложнее "протолкнуть" глобальный отбор внутрь первого пакета запросов, так как структура полей становится более жесткой.
Важно помнить про закладку Наборы данных в схеме СКД. Даже если запрос написан идеально, настройки колонок могут спровоцировать лишние отборы. Обратим внимание на следующие настройки:
Измерение. СКД приоритетно накладывает отборы именно на измерения виртуальных таблиц.UNION.Чтобы победить "лишние" отборы в СКД, следует придерживаться правила: чем сложнее запрос, тем меньше нужно полагаться на автозаполнение. Использование временных таблиц с четко определенными псевдонимами полей и явное описание доступных условий в фигурных скобках {} позволяют создавать предсказуемые и быстрые отчеты, где данные не исчезают из-за того, что система решила оптимизировать запрос за вас.