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