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