Как правильно передать Таблицу Значений в запрос и исправить ошибку «Таблица не найдена»

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Причина ошибки: Объект в памяти vs Таблица базы данных

Проанализируем исходную ситуацию. В коде автора таблица ТаблицаНаценок получена методом выгрузки из номенклатуры. Однако в тексте запроса к ней обращаются так, будто это постоянная таблица базы данных (например, справочник или регистр). Система не видит переменную ТаблицаНаценок внутри SQL-контекста, пока мы явно её туда не передадим.

Для исправления ситуации выполним два обязательных действия:

  1. В тексте запроса перед именем таблицы добавим символ &, указывая, что это параметр.
  2. В коде вызовем метод Запрос.УстановитьПараметр("ИмяПараметра", ТаблицаОбъект).

Посмотрим на исправленный фрагмент кода:


// Подготовка данных
ТаблицаНаценок = Номенклатура.Выгрузить(); 

Запрос = Новый Запрос;
// В тексте обязательно используем &ТаблицаНаценок
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТаблицаНаценок.ТМЦ КАК ТМЦ,
    |	ТаблицаНаценок.Партия КАК ПАРТИЯ
    |ПОМЕСТИТЬ ДанныеДокумента
    |ИЗ
    |	&ТаблицаНаценок КАК ТаблицаНаценок
    |;
    |...дальнейший текст запроса...";

// Передаем таблицу в запрос
Запрос.УстановитьПараметр("ТаблицаНаценок", ТаблицаНаценок);

Важный нюанс: Типизация колонок Таблицы Значений

Даже если мы правильно передали параметр, 1С может выдать ошибку «Неверные параметры», если колонки таблицы не имеют строго определенных типов. Если ТаблицаНаценок создается программно, крайне важно инициализировать её с использованием ОписаниеТипов. Если типы не определены (содержат Произвольный тип), запрос не сможет сопоставить эти данные с полями регистров.

Рассмотрим пример правильного создания таблицы перед передачей в запрос:


МассивТМЦ = Новый Массив;
МассивТМЦ.Добавить(Тип("СправочникСсылка.Номенклатура"));
ОписаниеТМЦ = Новый ОписаниеТипов(МассивТМЦ);

ТаблицаДляЗапроса = Новый ТаблицаЗначений;
ТаблицаДляЗапроса.Колонки.Добавить("ТМЦ", ОписаниеТМЦ);
ТаблицаДляЗапроса.Колонки.Добавить("Партия", Новый ОписаниеТипов("СправочникСсылка.ПартииНоменклатуры"));

Без жесткой типизации соединение с виртуальными таблицами (например, СрезПоследних) может работать некорректно или вызывать критические ошибки выполнения.

Работа с временными таблицами и методом ПОМЕСТИТЬ

В исходном сообщении автор использует конструкцию ПОМЕСТИТЬ тДокумента в конце запроса. Выясним причину, по которой РезультатЗапроса.Выгрузить() в этом случае вернет пустую таблицу. Когда последним словом в пакете запроса стоит ПОМЕСТИТЬ, данные записываются во временную таблицу в оперативной памяти (или в tempdb на сервере SQL), но не возвращаются в основной поток выполнения программы.

Чтобы получить результат, мы должны завершить пакет финальным выбором из этой временной таблицы:


// ... (предыдущие части запроса с ПОМЕСТИТЬ)
|;
|ВЫБРАТЬ
|	Т.ТМЦ,
|	Т.Партия,
|	Т.НаценкаИмпорт
|ИЗ
|	тДокумента КАК Т"; // Финальная выборка вернет данные в РезультатЗапроса

Оптимизация: Индексирование и Левое Соединение

При соединении временной таблицы с большими регистрами (как в случае с РегистрСведений.ЦеныТМЦ), производительность системы может значительно упасть. Проанализируем, как ускорить выполнение:

  1. Индексирование: Всегда добавляйте ИНДЕКСИРОВАТЬ ПО для полей, по которым происходит связь (ТМЦ, Партия).
  2. Параметры Виртуальных Таблиц: Вместо того чтобы выгружать весь срез последних и потом соединять его с документом, передайте список ТМЦ прямо в параметры виртуальной таблицы. Это «золотое правило» оптимизации 1С.

Посмотрим на оптимизированный вариант структуры запроса:


Запрос.Текст = 
    "ВЫБРАТЬ
    |	Таблица.ТМЦ КАК ТМЦ,
    |	Таблица.Партия КАК Партия
    |ПОМЕСТИТЬ ВтДанныеДокумента
    |ИЗ
    |	&ТаблицаНаценок КАК Таблица
    |ИНДЕКСИРОВАТЬ ПО
    |	ТМЦ,
    |	Партия
    |;
    |ВЫБРАТЬ
    |	ВтДанные.ТМЦ КАК ТМЦ,
    |	Цены.НаценкаИмпорт КАК НаценкаИмпорт
    |ИЗ
    |	ВтДанныеДокумента КАК ВтДанные
    |		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныТМЦ.СрезПоследних(&Период, 
    |			ТМЦ В (ВЫБРАТЬ ТМЦ ИЗ ВтДанныеДокумента)) КАК Цены
    |		ПО ВтДанные.ТМЦ = Цены.ТМЦ И ВтДанные.Партия = Цены.Партия";

Важно: Использование ЛЕВОЕ СОЕДИНЕНИЕ гарантирует, что мы не потеряем строки из документа, для которых еще не установлена наценка в регистре. В этом случае в поле НаценкаИмпорт просто придет значение NULL, которое можно обработать функцией ЕСТЬNULL(Цены.НаценкаИмпорт, 0).

Ошибки в синтаксисе (Опечатки)

При написании запросов вручную легко допустить опечатку, которую трудно заметить. В исходном сообщении была ошибка: ПО Регист.ТМЦ = ДанныеДокумента.ТМЦ. Пропущена буква «р» в псевдониме таблицы Регистр. Рекомендуем всегда использовать Конструктор запроса — это исключает подобные ошибки, так как псевдонимы и поля выбираются из списка.

Итоги

Для успешной работы с Таблицей Значений в запросе необходимо:

← На главную