Каждый разработчик 1С при работе с Системой компоновки данных (СКД) рано или поздно сталкивается с ситуацией, когда запрос, идеально работающий в обычной консоли запросов, начинает выдавать некорректные или урезанные данные при запуске в отчете СКД. Типичный пример такой проблемы — автоматическое наложение глобального периода отчета на виртуальные таблицы (например, Обороты, ОстаткиИОбороты), участвующие в левом соединении. В результате вместо полных исторических данных за все время мы получаем информацию только за выбранный пользователем месяц.
В этой статье мы подробно разберем, почему СКД ведет себя подобным образом, как устроен механизм автозаполнения и какими способами можно отключить или обойти автоматическое наложение фильтров на виртуальные таблицы.
Главным виновником такого поведения является включенный по умолчанию флаг «Автозаполнение» в схеме компоновки данных. Этот механизм создан для облегчения жизни разработчику: СКД анализирует текст запроса и автоматически пытается связать параметры виртуальных таблиц с глобальными параметрами отчета.
Когда компоновщик данных видит в запросе виртуальную таблицу оборотов без явно указанных параметров, например:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты КАК ТаблицаОтгрузок
ПО ТаблицаОплат.ЗаказКлиента = ТаблицаОтгрузок.ЗаказКлиента
Он автоматически преобразует этот кусок в результирующем SQL-запросе, неявно подставляя глобальные параметры периода:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода) КАК ТаблицаОтгрузок
Даже если мы попытаемся жестко прописать даты непосредственно в параметрах виртуальной таблицы в тексте запроса:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(ДАТАВРЕМЯ(2018, 1, 1), ДАТАВРЕМЯ(2018, 6, 1)) КАК ТаблицаОтгрузок
При включенном автозаполнении СКД все равно проигнорирует эти литералы и переопределит их значениями глобальных параметров отчета &НачалоПериода и &КонецПериода во время генерации итогового макета компоновки.
Для решения этой проблемы существует несколько профессиональных подходов. Рассмотрим их по шагам.
Один из самых простых и изящных способов «обмануть» автозаполнение СКД — явно передать в параметры виртуальной таблицы пустые даты (начало времен) внутри фигурных скобок. Фигурные скобки указывают системе компоновки, что данные параметры являются необязательными и управляются по особым правилам.
Изменим запрос следующим образом:
ВЫБРАТЬ
ТаблицаОплат.Менеджер КАК Менеджер,
ТаблицаОплат.ЗаказКлиента КАК ЗаказКлиента,
СУММА(ТаблицаОплат.Оплата) КАК Оплата,
СУММА(ЕСТЬNULL(ТаблицаОтгрузок.СуммаВыручкиРеглОборот, 0)) КАК Отгружено
ИЗ
ТаблицаОплат КАК ТаблицаОплат
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты({ДатаВремя(1,1,1)}, {ДатаВремя(1,1,1)}) КАК ТаблицаОтгрузок
ПО ТаблицаОплат.ЗаказКлиента = ТаблицаОтгрузок.ЗаказКлиента
СГРУППИРОВАТЬ ПО
ТаблицаОплат.Менеджер,
ТаблицаОплат.ЗаказКлиента
Как это работает: Указывая пустые даты {ДатаВремя(1,1,1)} в фигурных скобках, мы принудительно разрываем автоматическую связь этой виртуальной таблицы с глобальным периодом отчета. СКД понимает, что для данной таблицы заданы свои собственные границы (в данном случае — их отсутствие, то есть выборка за весь период существования базы данных), и оставляет их без изменений.
Если мы хотим решить проблему более системно, не прибегая к ручному написанию фигурных скобок в коде, мы можем воспользоваться специализированными инструментами конструктора запросов.
Выполним следующие шаги:
Настройки, заданные в секции «Компоновка данных», имеют наивысший приоритет. СКД поймет, что эти параметры контролируются разработчиком вручную, и автозаполнение не будет заменять их стандартными значениями.
Что делать, если нам все-таки нужно фильтровать виртуальную таблицу по периоду, но этот период должен отличаться от основного периода отчета? В таком случае нам необходимо явно объявить новые независимые параметры в фигурных скобках:
РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты({&НачалоПериодаОтгрузок}, {&КонецПериодаОтгрузок}) КАК ТаблицаОтгрузок
После изменения запроса выполним настройку в СКД:
&НачалоПериодаОтгрузок и &КонецПериодаОтгрузок.&НачалоПериода и &КонецПериода мы можем оставить стандартные настройки (они будут отвечать за фильтрацию основной таблицы оплат).Для сложных аналитических отчетов с большим количеством временных таблиц, вложенных запросов и нетривиальных левых соединений лучшей практикой считается полное отключение механизма автоматического заполнения.
Проанализируем этот подход подробнее:
При отключенном автозаполнении мы должны вручную прописать в фигурных скобках те поля, по которым СКД разрешено делать отборы. Например:
ВЫБРАТЬ
ТаблицаОплат.Менеджер КАК Менеджер {&Менеджер},
ТаблицаОплат.ЗаказКлиента КАК ЗаказКлиента {&ЗаказКлиента}
ИЗ
ТаблицаОплат КАК ТаблицаОплат
ГДЕ
ТаблицаОплат.Период МЕЖДУ &НачалоПериода И &КонецПериода
В этом случае виртуальная таблица левого соединения, для которой мы не описали фигурные скобки с параметрами периода, гарантированно останется нетронутой компоновщиком данных.
Часто разработчики наступают на эти грабли при реализации отчетов типа «Продажи за текущий период в сравнении с аналогичным периодом прошлого года». Если выполнять объединение двух виртуальных таблиц оборотов (за этот год и за прошлый год) в одном запросе с включенным автозаполнением, СКД принудительно приведет обе таблицы к одному и тому же глобальному периоду отчета. В итоге в обеих колонках отобразятся абсолютно одинаковые цифры.
Решением в данной ситуации является обязательное применение Способа 3 (переименование параметров в фигурных скобках для каждой из таблиц) или Способа 4 (отключение автозаполнения).
Используя предложенные методики, вы сможете полностью контролировать поведение СКД и получать ожидаемые результаты при работе с любыми виртуальными таблицами платформ 1С.