Как сравнить уникальный идентификатор и строку в запросе 1С

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

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

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

Почему возникает ошибка при сравнении типов

Давайте проанализируем ситуацию. В 1С тип УникальныйИдентификатор на уровне системы управления базами данных (СУБД) представляет собой 16-байтовое двоичное число (binary(16) или uniqueidentifier в MS SQL Server). В то же время строковое представление GUID — это текст из 36 символов. Для платформы это абсолютно разные сущности: «мальчик и девочка», как метко подметили участники обсуждения.

Функция ПРЕДСТАВЛЕНИЕ() в языке запросов предназначена исключительно для получения текстового описания объекта для нужд интерфейса. Она возвращает специальный тип, который нельзя использовать в условиях ГДЕ, конструкциях СОЕДИНЕНИЕ или СГРУППИРОВАТЬ ПО. Использовать ВЫРАЗИТЬ(Поле КАК СТРОКА) для типа УникальныйИдентификатор также не получится, так как платформа не поддерживает прямое приведение этого типа к строке внутри SQL-запроса.

Способ 1. Использование временных таблиц и таблицы значений

Если нам необходимо выполнить разовый запрос или отчет, где данные связаны через GUID и строку, самым правильным подходом будет предварительная подготовка данных на стороне встроенного языка. Рассмотрим этот алгоритм по шагам.

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


// 1. Получаем данные из документа с УИН
ЗапросПодготовка = Новый Запрос;
ЗапросПодготовка.Текст = 
"ВЫБРАТЬ
|   ДокументОбъект.Ссылка КАК Ссылка,
|   ДокументОбъект.УникальныйИдентификатор КАК УИН_Объект
|ИЗ
|   Документ.НашДокумент КАК ДокументОбъект";

ТаблицаДанных = ЗапросПодготовка.Выполнить().Выгрузить();

// 2. Создаем колонку со строковым представлением
ТаблицаДанных.Колонки.Добавить("УИН_Строка", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));

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

// 3. Передаем подготовленную таблицу в основной запрос
ЗапросОсновной = Новый Запрос;
ЗапросОсновной.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
ЗапросОсновной.УстановитьПараметр("ТаблицаСвязи", ТаблицаДанных);

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

Результат = ЗапросОсновной.Выполнить();

Этот метод надежен, так как гарантирует, что сравнение происходит на уровне строк. Однако помните о производительности: соединение по строковым полям длиной 36 символов работает медленнее, чем по ссылкам или числам.

Способ 2. Добавление индексированного реквизита в объект

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

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

  1. Добавим в документ или справочник дополнительный реквизит, например, УИН_Строка с типом Строка(36).
  2. Установим для этого реквизита свойство Индексировать (или Индексировать с дополнительным упорядочиванием).
  3. В модуле объекта в событии ПередЗаписью пропишем заполнение этого поля:

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ЭтоНовый() Или НЕ ЗначениеЗаполнено(УИН_Строка) Тогда
        УИН_Строка = Строка(ЭтотОбъект.УникальныйИдентификатор());
    КонецЕсли;
КонецПроцедуры

Теперь в любых запросах мы сможем напрямую связывать таблицы, используя это индексированное поле. Это обеспечит максимальную скорость выполнения запроса (Index Seek вместо Table Scan).

Способ 3. Получение ссылки по УИН через встроенный язык

Иногда задача стоит иначе: нужно найти ссылку на документ, зная его GUID. В этом случае не обязательно использовать сложные соединения в запросе. Мы можем воспользоваться методом менеджера объекта ПолучитьСсылку().

Разберем пример, когда у нас есть строка с GUID из внешнего источника:


// Строка, полученная из регистра или внешнего файла
СтрокаGUID = "550e8400-e29b-41d4-a716-446655440000";
НовыйGUID = Новый УникальныйИдентификатор(СтрокаGUID);

// Получаем ссылку напрямую, зная тип документа
СсылкаНаДокумент = Документы.ЗаказПокупателя.ПолучитьСсылку(НовыйGUID);

// Важно проверить, существует ли такой объект в базе
Если СсылкаНаДокумент.ПолучитьОбъект() = Неопределено Тогда
    Сообщить("Объект не найден!");
КонецЕсли;

Этот метод работает мгновенно и позволяет избежать написания громоздких запросов, если вам нужно обработать конкретный список идентификаторов.

Резюме и рекомендации

Мы проанализировали ситуацию и выяснили, что прямое сравнение типа УникальныйИдентификатор и Строка в запросе невозможно из-за архитектуры 1С. Подведем итоги наших решений:

Использование уникальных идентификаторов в качестве ключей связи — это мощный инструмент, но он требует понимания того, как 1С работает с типами данных на физическом уровне СУБД. Следуя приведенным выше инструкциям, вы сможете избежать ошибок несовместимости типов и обеспечить стабильную работу ваших запросов.

← На главную