При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда итоговый запрос, выполняемый платформой, существенно отличается от того, который был написан в конструкторе. СКД обладает интеллектуальным механизмом «оптимизации», который пытается «протолкнуть» пользовательские отборы как можно глубже в структуру запроса — во временные таблицы, вложенные запросы и части объединений (UNION ALL). Однако иногда эта «интеллектуальность» приводит к логическим ошибкам, особенно при расчете средних величин или использовании агрегатных функций. Рассмотрим, как управлять этим процессом и «отучить» СКД добавлять лишние условия.
Проанализируем ситуацию на примере. Допустим, мы рассчитываем среднее количество ставок в штатном расписании. В запросе используется объединение нескольких частей, где в первой части мы группируем данные по рабочим дням, а в последующих — выбираем данные на границы периода. Исходный фрагмент запроса выглядит так:
ВЫБРАТЬ
ВТРабочиеДни.ПозицияШтатногоРасписания КАК ПозицияШтатногоРасписания,
СУММА(ВТРабочиеДни.СтавокОткрыто) / КОЛИЧЕСТВО(ВТРабочиеДни.Дата) КАК СтавокОткрыто,
СУММА(ВТРабочиеДни.СтавокЗанято) / КОЛИЧЕСТВО(ВТРабочиеДни.Дата) КАК СтавокЗанято
ПОМЕСТИТЬ ВТВсеДанные
ИЗ
ВТРабочиеДни КАК ВТРабочиеДни
СГРУППИРОВАТЬ ПО
ВТРабочиеДни.ПозицияШтатногоРасписания
После компоновки СКД может добавить секцию ИМЕЮЩИЕ (HAVING), если пользователь установил отбор или если система решила отсечь нулевые значения. В результате запрос превращается в конструкцию с дополнительными фильтрами:
СГРУППИРОВАТЬ ПО
ВТРабочиеДни.ПозицияШтатногоРасписания
ИМЕЮЩИЕ
(СУММА(ВТРабочиеДни.СтавокОткрыто) / КОЛИЧЕСТВО(ВТРабочиеДни.Дата) <> &П3
ИЛИ СУММА(ВТРабочиеДни.СтавокЗанято) / КОЛИЧЕСТВО(ВТРабочиеДни.Дата) <> &П3)
Где &П3 — это параметр, равный нулю. Это происходит из-за того, что СКД пытается минимизировать объем данных, передаваемых между временными таблицами. Рассмотрим основные способы борьбы с этим поведением.
Самый радикальный и действенный метод — это отключение флага Автозаполнение на закладке «Наборы данных». Когда этот флаг включен, СКД автоматически анализирует текст запроса и делает все доступные поля доступными для отбора, группировки и порядка. При этом она сама решает, куда добавлять условия ГДЕ.
Разберем алгоритм действий при отключении автозаполнения:
Важно помнить: если мы отключаем автозаполнение, нам придется описывать все поля вручную. Поле, не указанное на закладке компоновки, станет недоступным для настроек пользователя.
Если мы не хотим полностью отказываться от удобства автозаполнения, воспользуемся специальным синтаксисом СКД — фигурными скобками {}. Это позволяет явно указать системе, в каком именно месте запроса должны применяться отборы.
Проанализируем ситуацию: если мы хотим, чтобы отбор по позиции штатного расписания применялся только к итоговому результату, а не к промежуточным временным таблицам, мы можем написать в конечном запросе пакета:
ВЫБРАТЬ
ВТВсеДанные.ПозицияШтатногоРасписания,
ВТВсеДанные.СтавокОткрыто
ИЗ
ВТВсеДанные КАК ВТВсеДанные
{ГДЕ
ВТВсеДанные.ПозицияШтатногоРасписания.*}
При наличии фигурных скобок СКД часто (хотя и не всегда, зависит от версии платформы и сложности запроса) отдает приоритет явным указаниям и перестает «проталкивать» условия в другие части пакета.
В конструкторе запроса 1С есть специальная закладка Компоновка данных, о которой часто забывают. Она позволяет управлять поведением полей без полного отключения автозаполнения. Выясним, как использовать ее возможности:
ВТРабочиеДни).ПозицияШтатногоРасписания.Механизм автозаполнения ориентируется на имена полей. Если в промежуточной таблице поле называется Организация_Техническая, а в результирующей — Организация, то при установке пользователем отбора по полю Организация, СКД не сможет автоматически сопоставить его с полем Организация_Техническая во временной таблице.
Посмотрим на пример логики:
ВЫБРАТЬ Ссылка КАК Позиция_Скрытая.ВЫБРАТЬ Позиция_Скрытая КАК ПозицияШтатногоРасписания.ПозицияШтатногоРасписания в итоговой выборке. Если пользователь наложит отбор, фильтр будет добавлен только в финальную секцию ГДЕ, так как во временной таблице поля с таким именем «не существует» для компоновщика.Часто проблема с лишними ИМЕЮЩИЕ возникает из-за того, что разработчик пытается вычислить среднее значение или сложные коэффициенты прямо в тексте запроса. С точки зрения СКД, правильнее возвращать «сырые» данные, а расчеты производить на закладке Ресурсы.
Рассмотрим, как это упрощает работу:
СтавокОткрыто пишем выражение: Сумма(СтавокОткрыто) / Количество(Различные Дата).ИМЕЮЩИЕ. Отборы будут накладываться на детальные записи, что работает гораздо предсказуемее.Мы проанализировали основные методы управления запросом в СКД. Подведем итог: если система мешает корректному расчету данных, добавляя свои условия, наиболее «чистым» решением является использование закладки Компоновка данных в конструкторе запроса для управления использованием полей в частях запроса. В особо сложных случаях следует отключать Автозаполнение или использовать фигурные скобки для явного указания мест фильтрации.