Разработчики 1С часто сталкиваются с парадоксальной ситуацией: сложный запрос, содержащий несколько временных таблиц, идеально выполняется в консоли запросов, но при попытке использовать его в качестве набора данных в Системе компоновки данных (СКД) выдает ошибку «Таблица не найдена». Чаще всего система «теряет» первую же временную таблицу. Проанализируем природу этого поведения и разберем по шагам все доступные способы решения задачи.
Основная причина кроется в механизме работы СКД. В отличие от консоли запросов, которая выполняет текст «как есть», СКД выступает в роли интеллектуального построителя. Она анализирует текущие настройки отчета (выбранные поля, группировки, отборы) и динамически перестраивает исходный запрос, чтобы исключить из него «лишние» данные. Если компоновщик «считает», что данные из конкретной временной таблицы не используются в итоговом результате или не влияют на него, он просто вырезает создание этой таблицы из финального запроса. Однако, если на эту таблицу остаются ссылки в последующих соединениях (особенно при использовании ВНУТРЕННЕЕ СОЕДИНЕНИЕ), выполнение прерывается с ошибкой.
Рассмотрим самый надежный программный способ заставить СКД «видеть» таблицу. В настройках набора данных есть колонка «Роли». Для полей, которые выбираются из проблемной временной таблицы, необходимо установить флаг «Обязательное».
Разберем, почему это помогает: когда мы помечаем поле как обязательное, мы даем компоновщику жесткое указание — это поле (и таблица-источник) должно присутствовать в конечном запросе вне зависимости от того, выбрал его пользователь в настройках отчета или нет. Проанализируем порядок действий:
Если ваша база данных использует механизм Дата-акселератора (копии базы данных), СКД может пытаться оптимизировать запрос для работы с копией, что иногда приводит к конфликтам с временными таблицами. Выясним причину: при определенных настройках система может решить, что данные в копии не требуют построения всех промежуточных звеньев.
В этом случае помогает установка параметра «Требуемая актуальность данных». Выполним следующие действия:
Иногда СКД игнорирует таблицу, если считает ее содержимое константным или не влияющим на фильтрацию. Посмотрим на «хитрость», которую применяют опытные разработчики: добавление условия, которое всегда истинно, но задействует поля таблицы.
Например, если у нас есть временная таблица ВремяЗаявки, которая «теряется», мы можем добавить в итоговом запросе условие:
ГДЕ
ВремяЗаявки.ЗаказС10До11 = ВремяЗаявки.ЗаказС10До11
Или, если мы работаем с количественными показателями:
ГДЕ
ВремяЗаявки.ЗаказС10До11 >= 0
Такое условие заставляет оптимизатор включить таблицу в план выполнения, так как поле таблицы участвует в секции фильтрации, которую компоновщик не может проигнорировать без глубокого анализа логики.
В запросе автора часто встречается конструкция ВНУТРЕННЕЕ СОЕДИНЕНИЕ ... ПО ИСТИНА. С точки зрения классического SQL — это CROSS JOIN. Однако СКД крайне плохо относится к таким соединениям, если из одной из таблиц не выбираются поля для вывода. Система считает такое соединение бессмысленным и выбрасывает таблицу.
Рассмотрим, как сделать связь более «явной» для системы. Мы можем добавить во все временные таблицы искусственный ключ связи:
// В каждой временной таблице добавляем поле:
ВЫБРАТЬ
1 КАК КлючСвязи,
...
ПОМЕСТИТЬ ВТ_Данные
Затем в финальном запросе заменим ПО ИСТИНА на логическую связь:
ИЗ
ВТ_1 КАК Таблица1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_2 КАК Таблица2
ПО Таблица1.КлючСвязи = Таблица2.КлючСвязи
Это создает прозрачную структуру зависимостей, которую компоновщик обрабатывает гораздо стабильнее.
Если ни один из методов не помогает, нам нужно проанализировать, какой именно текст запроса генерирует СКД в момент ошибки. Это можно сделать через отладку в коде вызова отчета. Посмотрим на пример кода для извлечения реального запроса:
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);
// В МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос будет текст
// который реально уходит на сервер СУБД.
Проанализируем полученный текст. Если в нем отсутствует секция ПОМЕСТИТЬ НазваниеТаблицы, значит, включено Автозаполнение, и СКД решила, что таблица не нужна. В этом случае стоит попробовать отключить флаг «Автозаполнение» в наборе данных и прописать все поля и связи вручную на вкладках «Поля» и «Связи наборов данных».
Не забывайте проверять Функциональные опции. Если объекты метаданных (документы или регистры), используемые в запросе, входят в состав функциональной опции, которая отключена в текущем сеансе, СКД молча вырежет обращение к ним. В консоли запросов функциональные опции обычно игнорируются, что и создает иллюзию «рабочего» запроса, который «ломается» в отчете.
Также обратите внимание на агрегатные функции. Если вы используете КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...) внутри временной таблицы без группировки (как в примере автора), попробуйте добавить фиктивную группировку по какому-либо полю, которое гарантированно есть в системе, чтобы структура таблицы выглядела для СКД более стандартно.