При разработке и доработке сложных отчетов или обработок выгрузки данных в 1С программисты часто сталкиваются с ошибкой выполнения запроса вида: «Ошибка при вызове метода контекста (Выполнить)... Таблица не найдена "ИмяТаблицы"». Особенно часто это происходит при левом соединении с временными таблицами, которые должны были быть подготовлены заранее.
В этой статье мы подробно разберем, почему возникает эта ошибка, как устроен жизненный цикл временных таблиц в платформе 1С:Предприятие, как правильно использовать объект МенеджерВременныхТаблиц и как шаг за шагом локализовать и исправить проблему в коде.
---
Когда платформа 1С выполняет запрос, содержащий инструкцию ПОМЕСТИТЬ ИмяВременнойТаблицы, физически на стороне СУБД (например, в MS SQL Server, PostgreSQL) создается реальная временная таблица (в базе данных tempdb или аналогичном системном хранилище). Чтобы СУБД знала о ее существовании при выполнении последующих запросов, платформа 1С использует связующий механизм — Менеджер временных таблиц (МВТ).
Если во втором запросе вы пытаетесь обратиться к временной таблице через конструкцию ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаДоп КАК ТаблицаДоп, а система выдает ошибку «Таблица не найдена», это может происходить по одной из следующих причин:
Перем, но ей не было присвоено значение Новый МенеджерВременныхТаблиц.Запрос, у которых не связан менеджер временных таблиц.ТаблицаДоп, просто не выполнился из-за логической ошибки (например, не заполнена исходная таблица значений или не установлена настройка интеграции).---
Давайте разберем по шагам, как локализовать место возникновения ошибки с помощью встроенного отладчика 1С. Многие начинающие разработчики совершают ошибку: они ставят точку останова, видят окно ошибки и не знают, куда смотреть дальше. Действовать нужно системно. Для интерактивной проверки и анализа выполнения запросов также подойдёт консоль запросов с поддержкой пакетных запросов и временных таблиц.
Установим точку останова непосредственно перед выполнением проблемного запроса (на строке Запрос.Выполнить()). Вызовем окно оценки выражений с помощью горячих клавиш Shift + F9 (или «Табло») и проверим состояние менеджера временных таблиц:
Запрос.МенеджерВременныхТаблиц. Если результатом вычисления является Неопределено, значит, в коде вообще не задан контейнер для хранения временных таблиц.МенеджерВременныхТаблиц), проверим коллекцию его таблиц с помощью выражения: Запрос.МенеджерВременныхТаблиц.Таблицы.ТаблицаДоп. Если список пуст или нужной таблицы там нет, значит, она не была создана ранее.Если таблицы в менеджере нет, нам нужно понять, где она должна была создаться. Используем глобальный поиск по конфигурации или по текущему модулю (Ctrl + F) со следующими поисковыми фразами:
ПОМЕСТИТЬ ТаблицаДоп"ТаблицаДоп"Важный нюанс: часто разработчики собирают тексты запросов динамически, складывая строки. В таком случае прямой поиск фразы ПОМЕСТИТЬ ТаблицаДоп может не дать результатов. Попробуйте поискать только имя таблицы ТаблицаДоп в кавычках или переменную, в которую может выгружаться эта таблица перед помещением в запрос.
---
Давайте рассмотрим конкретные программные сценарии решения проблемы в зависимости от того, как спроектирована логика вашей обработки.
Если в вашей обработке используются два последовательных запроса, очень важно явно инициализировать и связать их через один менеджер. Рассмотрим пример правильного кода:
// 1. Создаем единый менеджер временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;
// 2. Инициализируем первый запрос, который создаст таблицу
Запрос1 = Новый Запрос;
Запрос1.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос1.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Код КАК Код
|ПОМЕСТИТЬ ТаблицаДоп
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = ЛОЖЬ";
// Выполняем первый запрос. ТаблицаДоп теперь физически создана в СУБД
// и зарегистрирована в объекте МенеджерВТ
Запрос1.Выполнить();
// 3. Инициализируем второй (основной) запрос
Запрос2 = Новый Запрос;
// Передаем тот же самый менеджер во второй запрос!
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст =
"ВЫБРАТЬ
| ТаблицаДоп.Ссылка КАК Ссылка,
| ТаблицаДоп.Код КАК Код
|ИЗ
| ТаблицаДоп КАК ТаблицаДоп";
// Теперь этот запрос выполнится без ошибок
Результат = Запрос2.Выполнить().Выгрузить();
В практике интеграций (например, при выгрузке каталога товаров на маркетплейсы вроде Onliner) часто требуется сопоставить иерархию категорий 1С с категориями внешней площадки. Данные сопоставления хранятся в памяти в виде Таблицы Значений. Прямо соединить Таблицу Значений с базой данных в запросе невозможно — её нужно сначала принудительно «залить» в СУБД.
Проанализируем пример, как правильно передать готовую Таблицу Значений в качестве временной таблицы запроса:
// Предположим, у нас есть заполненная Таблица Значений "ТЗ_Сопоставление"
// с колонками: СтруктураЭлемент (СправочникСсылка) и СтруктураПодЭлемент (СправочникСсылка)
МенеджерВТ = Новый МенеджерВременныхТаблиц;
ЗапросПодготовки = Новый Запрос;
ЗапросПодготовки.МенеджерВременныхТаблиц = МенеджерВТ;
// Передаем ТЗ как параметр запроса
ЗапросПодготовки.УстановитьПараметр("ВнешняяТаблица", ТЗ_Сопоставление);
// Описываем типы колонок во временной таблице
ЗапросПодготовки.Текст =
"ВЫБРАТЬ
| ВнешнийИсточник.СтруктураЭлемент КАК СтруктураЭлемент,
| ВнешнийИсточник.СтруктураПодЭлемент КАК СтруктураПодЭлемент
|ПОМЕСТИТЬ ТаблицаДоп
|ИЗ
| &ВнешняяТаблица КАК ВнешнийИсточник";
// Заполняем ВТ "ТаблицаДоп" данными нашей ТЗ
ЗапросПодготовки.Выполнить();
// Теперь основной запрос сможет использовать эту таблицу
ЗапросОсновной = Новый Запрос;
ЗапросОсновной.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросОсновной.Текст =
"ВЫБРАТЬ
| ВложенныйЗапрос.Ссылка КАК СтруктураЭлемент,
| ВЫБОР
| КОГДА ТаблицаДоп.СтруктураПодЭлемент ЕСТЬ NULL
| ТОГДА ВложенныйЗапрос.Ссылка
| ИНАЧЕ ТаблицаДоп.StructureПодЭлемент
| КОНЕЦ КАК СтруктураПодЭлемент
|ИЗ
| Справочник.СтруктураНоменклатуры КАК ВложенныйЗапрос
| ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаДоп КАК ТаблицаДоп
| ПО ВложенныйЗапрос.Ссылка = ТаблицаДоп.СтруктураЭлемент";
РезультатЗапроса = ЗапросОсновной.Выполнить().Выгрузить();
Чтобы избежать путаницы с передачей менеджеров временных таблиц между разными объектами запросов, в 1С крайне рекомендуется использовать конструкцию Пакетного запроса. Пакетный запрос объединяет создание временных таблиц и получение итоговых данных в рамках одной транзакции и одного текста запроса. Части запроса разделяются символом точки с запятой ;. Для оптимизации работы с временными таблицами в сложных пакетах можно использовать обработку для расстановки инструкций уничтожения временных таблиц.
Рассмотрим, как выглядит лаконичный и защищенный от потери контекста пакетный запрос:
Запрос = Новый Запрос;
// При использовании пакета в рамках одного объекта Запрос
// Менеджер временных таблиц создается автоматически внутри платформы!
Запрос.Текст =
"ВЫБРАТЬ
| Сопоставление.Ссылка1 КАК СтруктураЭлемент,
| Сопоставление.Ссылка2 КАК СтруктураПодЭлемент
|ПОМЕСТИТЬ ТаблицаДоп
|ИЗ
| РегистрСведений.СопоставлениеКатегорий КАК Сопоставление
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВложенныйЗапрос.Ссылка КАК СтруктураЭлемент,
| ВЫБОР
| КОГДА ТаблицаДоп.СтруктураПодЭлемент ЕСТЬ NULL
| ТОГДА ВложенныйЗапрос.Ссылка
| ИНАЧЕ ТаблицаДоп.СтруктураПодЭлемент
| КОНЕЦ КАК СтруктураПодЭлемент
|ИЗ
| Справочник.СтруктураНоменклатуры КАК ВложенныйЗапрос
| ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаДоп КАК ТаблицаДоп
| ПО ВложенныйЗапрос.Ссылка = ТаблицаДоп.СтруктураЭлемент";
// Выполняем весь пакет за один раз
РезультатыПакета = Запрос.ВыполнитьПакет();
// РезультатыПакета[0] - это результат создания ВТ
// РезультатыПакета[1] - это результат нашего основного выборщика
ТаблицаРезультат = РезультатыПакета[1].Выгрузить();
---
Проанализируем контекст ошибки конкретно для обработки «ВыгрузкаОнлайнер2017». Ошибка происходит при попытке связать структуру номенклатуры 1С со вспомогательной таблицей соответствия категорий (ТаблицаДоп). Поле ОбъединятьСтруктуры говорит о том, что в обработке реализована возможность группировки нескольких веток категорий вашего склада в одну категорию на маркетплейсе.
Если данная обработка раньше работала, а теперь выдает ошибку, велика вероятность, что:
ТаблицаДоп было проигнорировано логикой кода.СтруктураНоменклатуры) изменилась, из-за чего первый запрос, формирующий временную таблицу, завершился аварийно, прервав цепочку выполнения.Для исправления ситуации обязательно проверьте, заполнены ли настройки категорий на форме обработки перед тем, как нажимать кнопку выгрузки в XML.