Как правильно выполнить запрос к таблице значений в 1С 8.3?

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

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

Обязательное условие: временные таблицы

Разберем типичную ситуацию: у нас есть объект ТаблицаЗначений, и мы хотим выбрать из нее данные обычным запросом. Если мы попытаемся написать прямой запрос к параметру, содержащему ТЗ, система выдаст ошибку: «Содержимое объекта данных может быть выбрано только во временную таблицу». Это связано с архитектурой платформы 8.3. В отличие от таблиц базы данных, ТЗ находится в оперативной памяти, и для выполнения SQL-подобных операций СУБД должна сначала «увидеть» эти данные в своем физическом пространстве (обычно это TempDB).

Рассмотрим правильный алгоритм действий. Чтобы выполнить запрос к ТЗ, необходимо поместить её во временную таблицу внутри пакетного запроса. Разберем по шагам структуру такого запроса:


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

Запрос.УстановитьПараметр("ТЗ", МояТаблицаЗначений);
Результат = Запрос.Выполнить();

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

Типизация колонок — залог успеха

Одна из самых частых причин, по которой запрос к ТЗ «отказывается» работать — отсутствие жесткой типизации колонок. Если колонки вашей таблицы созданы без указания типов, запрос не сможет определить структуру полей и выдаст ошибку еще на этапе компиляции.

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


ТЗ = Новый ТаблицаЗначений;
// Указываем типы данных явно
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));

// Заполняем данными
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Номенклатура = СсылкаНаТовар;
НоваяСтрока.Количество = 10;

Если вы используете таблицу, которая является данными формы (например, табличная часть на форме), помните, что напрямую передать ее в запрос нельзя. Сначала проанализируем ситуацию: таблица формы — это не совсем ТаблицаЗначений. Чтобы использовать ее в запросе, нужно выполнить метод Выгрузить(). Посмотрим на пример:


// Ошибка: Запрос.УстановитьПараметр("ТЗ", Объект.Товары); 
// Правильно:
ТаблицаДляЗапроса = Объект.Товары.Выгрузить();
Запрос.УстановитьПараметр("ТЗ", ТаблицаДляЗапроса);

Использование оператора ВЫРАЗИТЬ (CAST)

Выясним причину еще одной популярной ошибки. Допустим, в вашей ТЗ есть колонка со ссылками на справочник «Номенклатура», и вы хотите в запросе получить артикул этого товара через точку: ТЗ.Номенклатура.Артикул. В 1С 8.3 при работе с ТЗ такой подход часто вызывает ошибку «Поле не найдено».

Проблема в том, что механизм временных таблиц не всегда может автоматически «пробросить» связи от временной таблицы к таблицам базы данных. Для решения этой проблемы используйте функцию ВЫРАЗИТЬ. Это явно указывает системе тип ссылки. Рассмотрим пример:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   ВЫРАЗИТЬ(ТЗ.Номенклатура КАК Справочник.Номенклатура) КАК Номенклатура,
    |   ТЗ.Количество КАК Количество
    |ПОМЕСТИТЬ втДанные
    |ИЗ
    |   &ТЗ КАК ТЗ
    |;
    |
    |ВЫБРАТЬ
    |   втДанные.Номенклатура.Артикул КАК Артикул,
    |   втДанные.Количество
    |ИЗ
    |   втДанные КАК втДанные";

Использование ВЫРАЗИТЬ крайне важно для составных типов данных. Если в колонке могут быть ссылки разных типов, без явного приведения типов запрос может работать крайне медленно или выдавать некорректные результаты, так как СУБД придется пытаться соединиться со всеми возможными таблицами справочников, входящих в составной тип.

Выбор всех полей через звездочку (*)

Многие задаются вопросом: можно ли выбрать все поля ТЗ, не перечисляя их вручную? Посмотрим на нюансы. В первом запросе пакета (где происходит ПОМЕСТИТЬ) вы обязаны перечислить все колонки, которые хотите видеть во временной таблице. Оператор * здесь работать не будет, так как структура временной таблицы формируется именно в этот момент.

Однако во втором запросе пакета, когда вы выбираете данные уже из созданной временной таблицы, вы вполне можете использовать символ *. Разберем ситуацию на примере:


Запрос.Текст = 
    "ВЫБРАТЬ 
    |   ТЗ.Поле1, ТЗ.Поле2, ТЗ.Поле3 
    |ПОМЕСТИТЬ ВТ 
    |ИЗ &ТЗ КАК ТЗ;
    |
    |ВЫБРАТЬ * ИЗ ВТ"; // Здесь звездочка допустима

Важный совет: Несмотря на удобство звездочки, в профессиональной разработке 1С рекомендуется перечислять поля явно. Это повышает производительность (система не тянет лишние данные) и делает код более устойчивым к изменениям структуры таблиц.

Повышение производительности: индексация

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

При помещении ТЗ во временную таблицу крайне желательно проиндексировать поля, по которым будет идти связь. Это делается с помощью предложения ИНДЕКСИРОВАТЬ ПО:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТЗ.Контрагент КАК Контрагент,
    |   ТЗ.Сумма КАК Сумма
    |ПОМЕСТИТЬ втДанные
    |ИЗ
    |   &ТЗ КАК ТЗ
    |ИНДЕКСИРОВАТЬ ПО
    |   Контрагент";

Это создаст индекс во временной базе данных СУБД, что позволит выполнять соединения (JOIN) практически мгновенно даже на больших объемах данных.

Подведем итоги

Для успешного выполнения запроса к таблице значений в 1С 8.3 придерживайтесь следующих правил:

  1. Всегда используйте пакетный запрос с помещением ТЗ во временную таблицу через оператор ПОМЕСТИТЬ.
  2. Следите за типами данных: колонки ТЗ должны быть жестко типизированы через ОписаниеТипов.
  3. Выгружайте таблицы формы: если источник данных — элемент формы, используйте метод Выгрузить().
  4. Применяйте ВЫРАЗИТЬ: если нужно обращаться к реквизитам ссылок через точку.
  5. Используйте индексы: для больших таблиц всегда индексируйте ключевые поля связи во временной таблице.
  6. Менеджер временных таблиц: если нужно использовать одну и ту же ТЗ в нескольких разных объектах Запрос, создайте МенеджерВременныхТаблиц и назначьте его свойству МенеджерВременныхТаблиц вашего запроса.

Соблюдение этих простых рекомендаций поможет вам писать быстрый, стабильный и читаемый код при работе с коллекциями значений в памяти.

← На главную