При разработке или модификации внешних обработок, особенно печатных форм со сложными запросами, программисты 1С часто сталкиваются с ошибкой: Временная таблица уже существует "ИмяТаблицы". На первый взгляд, ошибка кажется абсурдной, ведь временные таблицы должны создаваться и уничтожаться в рамках одного выполнения запроса. Однако причина часто кроется не в логике самого запроса, а в особенностях работы платформы 1С.
Рассмотрим реальный пример: разработчик создает внешнюю печатную форму для документа КоммерческоеПредложениеКлиенту. Запрос, формирующий данные, является пакетным и использует несколько временных таблиц. При попытке выполнить печать система выдает ошибку.
Текст ошибки:
{(35, 11)}: Временная таблица уже существует "Товар1" ПОМЕСТИТЬ >Товар1
При этом, если скопировать текст запроса и выполнить его в консоли запросов, он отрабатывает без ошибок. Давайте разберем, почему так происходит и как это исправить.
В первую очередь посмотрим на фрагмент кода, где возникает проблема. Ошибка указывает на первую же инструкцию создания временной таблицы Товар1 в большом пакетном запросе.
Функция ПолучитьДанныеДляПечати(МассивОбъектов, ПараметрыПечати)
// ... пропущена подготовка параметров
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
Запрос.УстановитьПараметр("ОтображатьСкидки", ОтображатьСкидки);
Запрос.Текст =
"ВЫБРАТЬ
| Таблица.Ссылка КАК Ссылка,
| // ... другие поля
|ПОМЕСТИТЬ Товар1
|ИЗ
| Документ.КоммерческоеПредложениеКлиенту.Товары КАК Таблица
|ГДЕ
| Таблица.Ссылка В(&МассивОбъектов)
|;
|
|////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| // ... следующий пакет запроса, использующий Товар1
|";
// ... dalshe idet ogromnyy tekst paketnogo zaprosa
ПакетРезультатовЗапроса = Запрос.ВыполнитьПакет();
// ...
Возврат СтруктураДанныхДляПечати;
КонецФункции
Тот факт, что запрос работает в консоли, но не работает при вызове из внешней обработки, является ключевой подсказкой. Это означает, что синтаксис запроса корректен, но проблема заключается в контексте его выполнения. Существует несколько основных причин такого поведения.
Это самая частая причина подобных "плавающих" ошибок. Платформа 1С для ускорения работы кэширует скомпилированные версии внешних отчетов и обработок. Разберемся, как это приводит к нашей ошибке.
Механизм возникновения ошибки:
Товар1).Товар1.Есть два способа решить эту проблему.
Способ 1. Быстрый "обходной маневр"
Самый простой способ заставить платформу 1С забыть про старую версию обработки — это просто переименовать файл обработки (например, из ПечатьКП.epf в ПечатьКП_v2.epf). Для платформы это будет совершенно новый объект, который она загрузит с чистого листа, в новом контексте, где нет "мусорных" временных таблиц.
Способ 2. Правильная очистка кэша
Переименование файла — это хороший метод для быстрой отладки, но для системного решения лучше использовать стандартные механизмы очистки кэша.
/ClearCache./ClearCache можно убрать, он нужен только для однократной очистки.Даже если проблема связана с кэшем, хороший код должен быть устойчив к таким ситуациям. Язык запросов 1С предоставляет специальную инструкцию для принудительного удаления временных таблиц — УНИЧТОЖИТЬ.
Чтобы гарантировать, что ваш запрос всегда будет выполняться в "чистом" окружении, добавьте в самое начало пакетного запроса удаление всех временных таблиц, которые вы планируете создать. Менеджер запросов просто проигнорирует эту команду, если таблицы не существует, и удалит ее, если она по какой-то причине осталась от предыдущего неудачного выполнения.
Пример модифицированного кода:
Запрос.Текст =
"УНИЧТОЖИТЬ Товар1;
|УНИЧТОЖИТЬ ВременнаяТаблицаНаборыПодготовка;
|УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительноЧастьПервая;
|УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительноЧастьВторая;
|УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительно;
|УНИЧТОЖИТЬ ВременнаяТаблицаНаборы;
|
|ВЫБРАТЬ
| Таблица.Ссылка КАК Ссылка,
| // ... остальные поля
|ПОМЕСТИТЬ Товар1
|ИЗ
| Документ.КоммерческоеПредложениеКлиенту.Товары КАК Таблица
|ГДЕ
| Таблица.Ссылка В(&МассивОбъектов)
|;
|
|// ... остальные пакеты запроса
|";
Такой подход делает ваш код значительно более надежным и защищает от проблем с "мусором", оставшимся после аварийных завершений.
В исходном коде есть еще один важный момент, который мог стать первопричиной сбоя — динамическое формирование части текста запроса.
Запрос.Текст = СтрЗаменить(Запрос.Текст,
"&ТекстЗапросаКоэффициентУпаковки",
Справочники.УпаковкиЕдиницыИзмерения.ТекстЗапросаКоэффициентаУпаковки("Товары.Упаковка", "Товары.Номенклатура"));
Функция ТекстЗапросаКоэффициентаУпаковки возвращает большой кусок SQL-подобного кода, который вставляется в основной запрос. Если в этом генерируемом коде окажется синтаксическая ошибка (например, из-за новых данных в справочнике или изменений в конфигурации), то весь пакетный запрос аварийно завершится, что и приведет к проблеме с "зависшей" временной таблицей.
Чтобы диагностировать такие проблемы, необходимо увидеть итоговый текст запроса, который отправляется на выполнение.
Порядок действий для отладки:
Запрос.ВыполнитьПакет() добавьте код для вывода итогового текста в окно сообщений.
// ... после всех СтрЗаменить
ИтоговыйТекстЗапроса = Запрос.Текст;
// Выводим полный текст в окно сообщений для анализа
Сообщить(ИтоговыйТекстЗапроса);
ПакетРезультатовЗапроса = Запрос.ВыполнитьПакет();
Этот метод позволяет выявить скрытые ошибки, которые вносятся динамически и не видны при простом просмотре исходного кода обработки.
Ошибка Временная таблица уже существует редко говорит о логической ошибке в коде. Чаще всего это следствие одной из трех причин:
УНИЧТОЖИТЬ в начало пакетного запроса.Применяя эти подходы, вы сможете не только быстро исправить текущую ошибку, но и сделать свой код более надежным и простым в отладке в будущем.