При разработке на платформе 1С:Предприятие 8 часто возникает необходимость передать данные, подготовленные «в памяти» (в объекте ТаблицаЗначений), непосредственно в запрос для дальнейшего соединения с таблицами базы данных или выполнения сложных расчетов. Однако разработчики нередко сталкиваются с системной ошибкой «Тип не может быть выбран в запросе». Проанализируем причины этой ситуации, разберем ограничения платформы и найдем способы корректной передачи данных.
Ошибка возникает в тот момент, когда платформа пытается создать временную таблицу в СУБД (SQL Server, PostgreSQL и др.) на основе структуры вашей ТаблицыЗначений. Важно понимать, что запрос в 1С выполняется на стороне сервера базы данных. Это означает, что все типы данных, которые вы передаете во временную таблицу, должны иметь прямое соответствие типам данных в SQL.
Рассмотрим ситуацию: если в одной из колонок вашей таблицы значений находится объект Массив, Структура или СписокЗначений, платформа не может преобразовать этот «объект памяти 1С» в колонку таблицы SQL, так как СУБД не знает, как хранить и обрабатывать такие структуры внутри ячейки таблицы. Именно в этот момент выполнение кода прерывается с ошибкой «Тип не может быть выбран в запросе».
Для того чтобы успешно использовать таблицу значений как источник для запроса, все её колонки должны быть строго типизированы. Проанализируем, какие типы данных пройдут проверку, а какие — нет.
Разрешенные типы (SQL-совместимые):
Число, Строка, Дата, Булево.Категорически запрещенные типы:
Массив, Структура, Соответствие.СписокЗначений, ХранилищеЗначения.ДвоичныеДанные.Просто создать колонку и заполнить её данными недостаточно для стабильной работы запроса. Если тип колонки не определен явно, платформа попытается угадать его по первому значению в таблице. Если таблица пуста, запрос может выдать ошибку или неверно проиндексировать данные. Поэтому мы всегда должны использовать объект ОписаниеТипов с указанием квалификаторов.
Рассмотрим пример правильной инициализации таблицы значений для последующей передачи в запрос:
// Создаем описание типов для строки с ограничением длины
КвалификаторыСтроки = Новый КвалификаторыСтроки(150);
ОписаниеСтрока = Новый ОписаниеТипов("Строка",,,, КвалификаторыСтроки);
// Создаем описание типов для числа с точностью
КвалификаторыЧисла = Новый КвалификаторыЧисла(15, 2);
ОписаниеЧисло = Новый ОписаниеТипов("Число", КвалификаторыЧисла);
// Инициализируем таблицу
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблицаДанных.Колонки.Добавить("Количество", ОписаниеЧисло);
ТаблицаДанных.Колонки.Добавить("Комментарий", ОписаниеСтрока);
ТаблицаДанных.Колонки.Добавить("ФлагАктивности", Новый ОписаниеТипов("Булево"));
Обратите внимание: если вы используете тип Булево, убедитесь, что в колонке нет значений Неопределено. Часто ошибка «Тип не может быть выбран» возникает именно из-за того, что в типизированную колонку Булево попало значение другого типа или пустая ссылка, которую платформа не смогла интерпретировать.
Иногда разработчики сообщают, что даже при явном описании типа Булево возникает та же ошибка. Проанализируем ситуацию подробнее. Это может происходить в двух случаях:
ОписаниеТипов или при обращении в тексте запроса.Массив), вся колонка целиком станет «невыбираемой» для запроса.Если ваша бизнес-логика требует обработки массивов внутри запроса, мы должны применить один из способов трансформации данных. Рассмотрим два эффективных метода.
Вместо того чтобы хранить массив в одной колонке, мы создаем для каждого элемента массива отдельную строку в таблице значений. Проанализируем пример: если у клиента есть массив из трех офисов, в итоговой таблице будет три строки с одним и тем же клиентом, но разными офисами.
// Предположим, у нас есть структура: Клиент -> МассивОфисов
Для Каждого СтрокаМассива Из ИсходныеДанные Цикл
Для Каждого ТекущийОфис Из СтрокаМассива.МассивОфисов Цикл
НоваяСтрока = ТаблицаДляЗапроса.Добавить();
НоваяСтрока.Клиент = СтрокаМассива.Клиент;
НоваяСтрока.Офис = ТекущийОфис; // Теперь здесь ссылка, а не массив
КонецЦикла;
КонецЦикла;
Если массив — это просто список значений для фильтрации, его можно передать в запрос как отдельный параметр или как вторую временную таблицу. В самом запросе мы выполним ВНУТРЕННЕЕ СОЕДИНЕНИЕ или будем использовать оператор В (ВЫБРАТЬ...).
Чтобы избежать подобных проблем в будущем, придерживайтесь следующих правил при работе с таблицами значений в запросах:
Таблица.Колонки.Добавить("Имя") без второго параметра.Неопределено в тех колонках, где предполагаются только ссылки или примитивные типы.Соблюдение этих принципов позволит вам избежать ошибки «Тип не может быть выбран в запросе» и сделает ваш код более надежным и производительным.