При разработке сложных механизмов интеграции или обмена данными программисты 1С часто сталкиваются с необходимостью использовать тип УникальныйИдентификатор прямо в запросах. Типичный сценарий: получение данных из регистра, помещение их в таблицу значений (ТЗ) на форме, а затем попытка использовать эту таблицу как источник для другого запроса через временные таблицы. Именно на этом этапе часто возникает неприятная ошибка: «Тип не может быть выбран в запросе».
В этой статье мы подробно разберем, почему возникает эта проблема, как она связана с версиями платформы «1С:Предприятие» и какие существуют способы её обхода, если обновить платформу прямо сейчас невозможно.
Давайте проанализируем ситуацию, с которой столкнулся автор темы. Имеется регистр сведений, где одним из измерений является УникальныйИдентификатор. Проблем с выборкой данных из самого регистра нет. Однако, как только мы пытаемся передать таблицу значений, содержащую колонку с этим типом, во временную таблицу (ВТ) запроса, система выдает отказ.
Рассмотрим пример проблемного кода:
// Предположим, СписокСообщений — это ТаблицаЗначений с колонкой ИдентификаторСообщения (тип УникальныйИдентификатор)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПолученныеСообщения.Дата,
| ПолученныеСообщения.ИдентификаторСообщения
|ПОМЕСТИТЬ ВТ_Сообщения
|ИЗ
| &СписокСообщений КАК ПолученныеСообщения;
|
|ВЫБРАТЬ
| *
|ИЗ
| ВТ_Сообщения КАК Таблица";
Запрос.УстановитьПараметр("СписокСообщений", СписокСообщений);
Результат = Запрос.Выполнить(); // Именно здесь происходит падение с ошибкой
Причина кроется в том, как платформа 1С транслирует объекты из оперативной памяти (Таблица Значений) в физические таблицы СУБД (SQL Server, PostgreSQL и др.). До определенных релизов механизм создания временных таблиц просто «не умел» сопоставлять внутренний тип 1С УникальныйИдентификатор с соответствующими типами в базе данных при передаче ТЗ в качестве параметра.
Самый правильный и современный способ решить проблему — убедиться, что вы используете актуальную версию платформы. Ограничение на использование типа УникальныйИдентификатор в колонках таблиц значений для запросов было официально снято.
Проанализируем хронологию исправлений:
УникальныйИдентификатор в запросах стала полноценной. Платформа научилась корректно типизировать такие колонки во временных таблицах.Если ваша конфигурация работает на платформе версии 8.3.13 и выше, вам достаточно просто убедиться, что колонка в Таблице Значений типизирована. Если ТЗ создается динамически, обязательно указывайте тип при добавлении колонки:
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("УникальныйИдентификатор"));
ОписаниеТипаУИД = Новый ОписаниеТипов(МассивТипов);
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ИдентификаторСообщения", ОписаниеТипаУИД);
Если по каким-то причинам проект жестко привязан к старой версии платформы (например, 8.3.10), то единственным надежным способом остается использование строкового представления идентификатора. Рассмотрим, как это реализовать эффективно.
Проанализируем шаги преобразования:
Строка(36).Строка(УИД).
// Подготовка данных для старых версий платформ
ТЗ = СписокСообщений.Скопировать();
ТЗ.Колонки.Добавить("ИдентификаторСтрокой", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));
Для Каждого Стр Из ТЗ Цикл
Стр.ИдентификаторСтрокой = Строка(Стр.ИдентификаторСообщения);
КонецЦикла;
// В запросе используем ИдентификаторСтрокой вместо ИдентификаторСообщения
Важное замечание по производительности: Как отмечали участники обсуждения, использование строк вместо «родного» типа UUID может замедлить работу запроса на больших объемах данных. Это связано с тем, что индекс по строке (36 символов в кодировке UTF-16 занимает 72 байта) работает медленнее и занимает больше места, чем индекс по 16-байтовому бинарному представлению УникальныйИдентификатор. Если в вашей таблице миллионы записей, старайтесь всё же обновить платформу.
Выясним одну важную деталь, которая часто вводит в заблуждение начинающих разработчиков. Обратите внимание на разницу в поведении параметров:
Использование в условии ГДЕ ... В (&Массив)
Если вы просто передаете список идентификаторов в массив и используете его в условии запроса, это будет работать даже на старых версиях платформ.
МассивУИД = Новый Массив;
МассивУИД.Добавить(Новый УникальныйИдентификатор("..."));
Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ РегистрСведений.Данные ГДЕ Идентификатор В (&МассивУИД)");
Запрос.УстановитьПараметр("МассивУИД", МассивУИД);
// Это сработает везде!
Помещение во Временную Таблицу
Ошибка возникает только тогда, когда идентификатор является частью структуры таблицы, которую вы пытаетесь «закачать» в SQL через ПОМЕСТИТЬ. Если вам нужно просто отфильтровать данные, используйте массив. Если же вам нужно соединить (JOIN) вашу таблицу с данными БД по этому полю — придется использовать способы, описанные выше.
Давайте разберем, почему программисты так борются за тип УникальныйИдентификатор. В базе данных SQL Server этот тип хранится как uniqueidentifier (16 байт). В PostgreSQL это тип uuid.
Сравним с хранением строки:
Поэтому, если ваша задача подразумевает высоконагруженную работу с измерениями регистров, всегда отдавайте предпочтение оригинальному типу УникальныйИдентификатор, даже если это требует обновления версии платформы на сервере.
Мы выяснили, что ошибка «Тип не может быть выбран в запросе» при работе с GUID — это историческое ограничение платформы «1С:Предприятие 8.3», которое было успешно устранено в ветке 8.3.13.
Для решения проблемы рекомендуем придерживаться следующего алгоритма:
Строка(36), заполняя её через Строка(УИД) перед передачей в запрос.Массив с элементами УникальныйИдентификатор — это работает на всех релизах.Рассмотренные подходы позволят вам эффективно работать с уникальными идентификаторами, сохраняя производительность системы и чистоту кода.