Как исправить ошибку "Временная таблица уже существует" во внешней обработке 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке или модификации внешних обработок, особенно печатных форм со сложными запросами, программисты 1С часто сталкиваются с ошибкой: Временная таблица уже существует "ИмяТаблицы". На первый взгляд, ошибка кажется абсурдной, ведь временные таблицы должны создаваться и уничтожаться в рамках одного выполнения запроса. Однако причина часто кроется не в логике самого запроса, а в особенностях работы платформы 1С.

Рассмотрим реальный пример: разработчик создает внешнюю печатную форму для документа КоммерческоеПредложениеКлиенту. Запрос, формирующий данные, является пакетным и использует несколько временных таблиц. При попытке выполнить печать система выдает ошибку.

Текст ошибки:

{(35, 11)}: Временная таблица уже существует "Товар1" ПОМЕСТИТЬ >Товар1

При этом, если скопировать текст запроса и выполнить его в консоли запросов, он отрабатывает без ошибок. Давайте разберем, почему так происходит и как это исправить.

Анализ исходного кода и ситуации

В первую очередь посмотрим на фрагмент кода, где возникает проблема. Ошибка указывает на первую же инструкцию создания временной таблицы Товар1 в большом пакетном запросе.


Функция ПолучитьДанныеДляПечати(МассивОбъектов, ПараметрыПечати)
    // ... пропущена подготовка параметров
    
    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
    Запрос.УстановитьПараметр("ОтображатьСкидки", ОтображатьСкидки);

    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Таблица.Ссылка КАК Ссылка,
    |    // ... другие поля
    |ПОМЕСТИТЬ Товар1
    |ИЗ
    |    Документ.КоммерческоеПредложениеКлиенту.Товары КАК Таблица
    |ГДЕ
    |    Таблица.Ссылка В(&МассивОбъектов)
    |;
    |
    |////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    // ... следующий пакет запроса, использующий Товар1
    |";
    
    // ... dalshe idet ogromnyy tekst paketnogo zaprosa
    
    ПакетРезультатовЗапроса = Запрос.ВыполнитьПакет();
    
    // ...
    
    Возврат СтруктураДанныхДляПечати;
КонецФункции

Тот факт, что запрос работает в консоли, но не работает при вызове из внешней обработки, является ключевой подсказкой. Это означает, что синтаксис запроса корректен, но проблема заключается в контексте его выполнения. Существует несколько основных причин такого поведения.

Решение 1: Проблема с кэшированием внешней обработки

Это самая частая причина подобных "плавающих" ошибок. Платформа 1С для ускорения работы кэширует скомпилированные версии внешних отчетов и обработок. Разберемся, как это приводит к нашей ошибке.

Механизм возникновения ошибки:

  1. Вы запускаете внешнюю обработку. Платформа выполняет код.
  2. В процессе выполнения пакетного запроса происходит какая-то другая, возможно, скрытая ошибка (например, из-за некорректных данных или ошибки в динамически формируемой части запроса).
  3. Выполнение прерывается аварийно. Пакет запросов не завершается штатно, и менеджер временных таблиц не успевает удалить уже созданные таблицы (в нашем случае — Товар1).
  4. Вы исправляете код, сохраняете обработку и пытаетесь запустить ее снова.
  5. Платформа, вместо того чтобы загрузить файл с диска, подгружает старую версию из кэша, которая работает в том же сеансе, где "зависла" временная таблица Товар1.
  6. Новая попытка выполнения натыкается на уже существующую таблицу и выдает ошибку.

Есть два способа решить эту проблему.

Способ 1. Быстрый "обходной маневр"

Самый простой способ заставить платформу 1С забыть про старую версию обработки — это просто переименовать файл обработки (например, из ПечатьКП.epf в ПечатьКП_v2.epf). Для платформы это будет совершенно новый объект, который она загрузит с чистого листа, в новом контексте, где нет "мусорных" временных таблиц.

Способ 2. Правильная очистка кэша

Переименование файла — это хороший метод для быстрой отладки, но для системного решения лучше использовать стандартные механизмы очистки кэша.

  1. Закройте все сеансы 1С:Предприятие.
  2. В окне запуска 1С выберите вашу информационную базу и нажмите кнопку "Изменить".
  3. Нажмите "Далее", не меняя настроек, пока не дойдете до последнего окна.
  4. В поле "Дополнительные параметры запуска" впишите команду: /ClearCache.
  5. Сохраните изменения и запустите 1С в режиме Предприятия. База запустится немного дольше обычного, так как будет пересоздавать весь кэш.
  6. После успешного запуска параметр /ClearCache можно убрать, он нужен только для однократной очистки.

Решение 2: Защита кода с помощью инструкции "УНИЧТОЖИТЬ"

Даже если проблема связана с кэшем, хороший код должен быть устойчив к таким ситуациям. Язык запросов 1С предоставляет специальную инструкцию для принудительного удаления временных таблиц — УНИЧТОЖИТЬ.

Чтобы гарантировать, что ваш запрос всегда будет выполняться в "чистом" окружении, добавьте в самое начало пакетного запроса удаление всех временных таблиц, которые вы планируете создать. Менеджер запросов просто проигнорирует эту команду, если таблицы не существует, и удалит ее, если она по какой-то причине осталась от предыдущего неудачного выполнения.

Пример модифицированного кода:


Запрос.Текст = 
    "УНИЧТОЖИТЬ Товар1;
    |УНИЧТОЖИТЬ ВременнаяТаблицаНаборыПодготовка;
    |УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительноЧастьПервая;
    |УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительноЧастьВторая;
    |УНИЧТОЖИТЬ ВременнаяТаблицаНаборыДополнительно;
    |УНИЧТОЖИТЬ ВременнаяТаблицаНаборы;
    |
    |ВЫБРАТЬ
    |    Таблица.Ссылка КАК Ссылка,
    |    // ... остальные поля
    |ПОМЕСТИТЬ Товар1
    |ИЗ
    |    Документ.КоммерческоеПредложениеКлиенту.Товары КАК Таблица
    |ГДЕ
    |    Таблица.Ссылка В(&МассивОбъектов)
    |;
    |
    |// ... остальные пакеты запроса
    |";

Такой подход делает ваш код значительно более надежным и защищает от проблем с "мусором", оставшимся после аварийных завершений.

Решение 3: Отладка динамически формируемых запросов

В исходном коде есть еще один важный момент, который мог стать первопричиной сбоя — динамическое формирование части текста запроса.


Запрос.Текст = СтрЗаменить(Запрос.Текст, 
    "&ТекстЗапросаКоэффициентУпаковки", 
    Справочники.УпаковкиЕдиницыИзмерения.ТекстЗапросаКоэффициентаУпаковки("Товары.Упаковка", "Товары.Номенклатура"));

Функция ТекстЗапросаКоэффициентаУпаковки возвращает большой кусок SQL-подобного кода, который вставляется в основной запрос. Если в этом генерируемом коде окажется синтаксическая ошибка (например, из-за новых данных в справочнике или изменений в конфигурации), то весь пакетный запрос аварийно завершится, что и приведет к проблеме с "зависшей" временной таблицей.

Чтобы диагностировать такие проблемы, необходимо увидеть итоговый текст запроса, который отправляется на выполнение.

Порядок действий для отладки:

  1. Перед строкой Запрос.ВыполнитьПакет() добавьте код для вывода итогового текста в окно сообщений.
  2. 
    // ... после всех СтрЗаменить
    ИтоговыйТекстЗапроса = Запрос.Текст;
    
    // Выводим полный текст в окно сообщений для анализа
    Сообщить(ИтоговыйТекстЗапроса);
    
    ПакетРезультатовЗапроса = Запрос.ВыполнитьПакет();
    
  3. Запустите обработку.
  4. Скопируйте полный текст запроса из окна сообщений.
  5. Вставьте его в консоль запросов и попробуйте выполнить. Консоль укажет на конкретное место синтаксической ошибки, если она есть.

Этот метод позволяет выявить скрытые ошибки, которые вносятся динамически и не видны при простом просмотре исходного кода обработки.

Выводы

Ошибка Временная таблица уже существует редко говорит о логической ошибке в коде. Чаще всего это следствие одной из трех причин:

  1. Кэширование платформой. Самая частая причина. Решается очисткой кэша или переименованием файла обработки.
  2. Отсутствие "защиты" в коде. Запрос не является отказоустойчивым. Решается добавлением инструкций УНИЧТОЖИТЬ в начало пакетного запроса.
  3. Скрытая ошибка в динамической части запроса. Она вызывает первоначальный сбой. Диагностируется путем вывода итогового текста запроса и его анализа в консоли.

Применяя эти подходы, вы сможете не только быстро исправить текущую ошибку, но и сделать свой код более надежным и простым в отладке в будущем.

← На главную