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

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

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

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

Выясняем причину: коварный союз ОБЪЕДИНИТЬ и оптимизации СКД

Проблема кроется не в ошибке платформы 1С, а в совместной работе двух мощных механизмов: стандартного поведения оператора ОБЪЕДИНИТЬ в языке запросов и интеллектуальной оптимизации, которую выполняет СКД.

  1. Поведение оператора ОБЪЕДИНИТЬ (UNION). В языке запросов 1С, как и в стандартном SQL, оператор ОБЪЕДИНИТЬ предназначен для слияния результатов нескольких запросов, но с одним важным нюансом: он возвращает только уникальные строки. Если после объединения в результирующем наборе окажутся две абсолютно одинаковые строки, одна из них будет отброшена. Это аналог выполнения ВЫБРАТЬ РАЗЛИЧНЫЕ для всего объединенного набора данных.
  2. Оптимизация запроса системой СКД. СКД — это умная система. Перед тем как выполнить ваш запрос, она анализирует настройки отчета: какие поля выбраны для вывода, какие используются в группировках, отборах, сортировках. На основе этого анализа СКД модифицирует исходный текст запроса, чтобы получить из базы данных только те данные, которые действительно нужны. Если какое-то поле из вашего запроса (особенно из промежуточной временной таблицы) не используется ни в одной настройке, СКД может просто вырезать его из текста запроса для повышения производительности.

Теперь сложим эти два фактора вместе. Рассмотрим пример из исходной проблемы.

Временная таблица создается так:


ВЫБРАТЬ
    "а" КАК Буква,
    "б" КАК Буква2,
    1 КАК Ключ
ПОМЕСТИТЬ Таб
ОБЪЕДИНИТЬ
ВЫБРАТЬ
    "а",
    "в",
    1
...

Изначально строки ("а", "б", 1) и ("а", "в", 1) уникальны благодаря полю Буква2. Но в настройках отчета мы убираем поле Буква2 из вывода. СКД видит это и "оптимизирует" запрос, который создает временную таблицу, удаляя из него колонку Буква2. В результате запрос для базы данных превращается в нечто подобное:


ВЫБРАТЬ
    "а" КАК Буква,
    1 КАК Ключ
ПОМЕСТИТЬ Таб
ОБЪЕДИНИТЬ
ВЫБРАТЬ
    "а",
    1
...

Теперь обе строки стали одинаковыми: ("а", 1). И тут в дело вступает оператор ОБЪЕДИНИТЬ, который, как мы помним, удаляет дубликаты. В итоге во временную таблицу попадает только одна из этих строк, а не две. Расчеты по полю Ключ, естественно, оказываются неверными.

Решение 1: Правильное использование оператора ОБЪЕДИНИТЬ ВСЕ

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

Этот оператор не выполняет проверку на уникальность, что делает его не только более предсказуемым в контексте СКД, но и более быстрым. Исправим исходный запрос:


ВЫБРАТЬ
    "а" КАК Буква,
    "б" КАК Буква2,
    0 КАК Ключ
ПОМЕСТИТЬ Таб
ОБЪЕДИНИТЬ ВСЕ // <-- Вот ключевое изменение
ВЫБРАТЬ
    "а",
    "б",
    1
ОБЪЕДИНИТЬ ВСЕ // <-- И здесь
ВЫБРАТЬ
    "а",
    "в",
    1
... и так далее для всех частей запроса

Теперь, даже если СКД уберет поле Буква2, оператор ОБЪЕДИНИТЬ ВСЕ не будет удалять строки, и во временной таблице окажутся все записи. Это основной и рекомендуемый способ решения проблемы.

Решение 2: Управление оптимизацией СКД через роли полей

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

Для этого в СКД существует механизм ролей полей. Он позволяет указать, как система должна воспринимать то или иное поле.

Как это сделать:

  1. Откройте схему компоновки данных вашего отчета.
  2. Перейдите на вкладку "Наборы данных" и выберите ваш набор данных типа "Запрос".
  3. В нижней части окна вы увидите список полей набора данных. Перейдите на вкладку "Роли".
  4. Найдите в списке поле, которое СКД не должна удалять (в нашем примере это Буква2).
  5. Установите для этого поля флажок в колонке "Обязательное".

Установка этого флажка является прямым указанием для СКД: "Это поле критически важно для логики запроса. Всегда включай его в выборку, даже если оно не выводится в отчет и не используется в настройках".

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

Дополнительные способы контроля над СКД

Существуют и более радикальные методы управления поведением СКД, которые стоит знать, но применять с осторожностью.

Отключение свойства "Автозаполнение"

У набора данных "Запрос" есть свойство Автозаполнение. По умолчанию оно включено, и именно оно позволяет СКД анализировать и изменять ваш запрос. Если его отключить, СКД будет выполнять текст запроса "как есть", без каких-либо модификаций. Плюсы: вы получаете полный контроль над текстом запроса. Минусы: отключаются многие удобные функции СКД, например, автоматическое создание параметров для виртуальных таблиц (период, условия и т.д.). Все параметры придется описывать вручную. Этот метод стоит использовать в крайних случаях.

Управление оптимизацией соединений

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

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

Понимание этих принципов позволит вам создавать надежные и предсказуемые отчеты на СКД, полностью контролируя процесс получения данных.

← На главную