Почему возникает ошибка Тип не может быть выбран в запросе при использовании таблицы значений?

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

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

Причина возникновения ошибки

Ошибка возникает в тот момент, когда платформа пытается создать временную таблицу в СУБД (SQL Server, PostgreSQL и др.) на основе структуры вашей ТаблицыЗначений. Важно понимать, что запрос в 1С выполняется на стороне сервера базы данных. Это означает, что все типы данных, которые вы передаете во временную таблицу, должны иметь прямое соответствие типам данных в SQL.

Рассмотрим ситуацию: если в одной из колонок вашей таблицы значений находится объект Массив, Структура или СписокЗначений, платформа не может преобразовать этот «объект памяти 1С» в колонку таблицы SQL, так как СУБД не знает, как хранить и обрабатывать такие структуры внутри ячейки таблицы. Именно в этот момент выполнение кода прерывается с ошибкой «Тип не может быть выбран в запросе».

Разберем допустимые и запрещенные типы данных

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

Разрешенные типы (SQL-совместимые):

Категорически запрещенные типы:

Как правильно описывать типы колонок

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

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


// Создаем описание типов для строки с ограничением длины
КвалификаторыСтроки = Новый КвалификаторыСтроки(150);
ОписаниеСтрока = Новый ОписаниеТипов("Строка",,,, КвалификаторыСтроки);

// Создаем описание типов для числа с точностью
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2);
ОписаниеЧисло = Новый ОписаниеТипов("Число", КвалификаторыЧисла);

// Инициализируем таблицу
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаДанных.Колонки.Добавить("Количество", ОписаниеЧисло);
ТаблицаДанных.Колонки.Добавить("Комментарий", ОписаниеСтрока);
ТаблицаДанных.Колонки.Добавить("ФлагАктивности", Новый ОписаниеТипов("Булево"));

Обратите внимание: если вы используете тип Булево, убедитесь, что в колонке нет значений Неопределено. Часто ошибка «Тип не может быть выбран» возникает именно из-за того, что в типизированную колонку Булево попало значение другого типа или пустая ссылка, которую платформа не смогла интерпретировать.

Выясняем причины проблем с типом Булево

Иногда разработчики сообщают, что даже при явном описании типа Булево возникает та же ошибка. Проанализируем ситуацию подробнее. Это может происходить в двух случаях:

  1. Синтаксические ошибки: Опечатка в имени колонки при добавлении в ОписаниеТипов или при обращении в тексте запроса.
  2. Смешанные типы: Если колонка определена как составной тип, и в массив типов случайно попал недопустимый объект (например, Массив), вся колонка целиком станет «невыбираемой» для запроса.

Как передать данные из Массива в запрос

Если ваша бизнес-логика требует обработки массивов внутри запроса, мы должны применить один из способов трансформации данных. Рассмотрим два эффективных метода.

Вариант 1: Развертывание (Flattening)

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


// Предположим, у нас есть структура: Клиент -> МассивОфисов
Для Каждого СтрокаМассива Из ИсходныеДанные Цикл
    Для Каждого ТекущийОфис Из СтрокаМассива.МассивОфисов Цикл
        НоваяСтрока = ТаблицаДляЗапроса.Добавить();
        НоваяСтрока.Клиент = СтрокаМассива.Клиент;
        НоваяСтрока.Офис = ТекущийОфис; // Теперь здесь ссылка, а не массив
    КонецЦикла;
КонецЦикла;

Вариант 2: Использование вспомогательной временной таблицы

Если массив — это просто список значений для фильтрации, его можно передать в запрос как отдельный параметр или как вторую временную таблицу. В самом запросе мы выполним ВНУТРЕННЕЕ СОЕДИНЕНИЕ или будем использовать оператор В (ВЫБРАТЬ...).

Рекомендации по предотвращению ошибок

Чтобы избежать подобных проблем в будущем, придерживайтесь следующих правил при работе с таблицами значений в запросах:

Соблюдение этих принципов позволит вам избежать ошибки «Тип не может быть выбран в запросе» и сделает ваш код более надежным и производительным.

← На главную