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

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

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

Выясняем причину: почему не работает ВЫРАЗИТЬ КАК Строка

Многие начинающие разработчики пытаются решить задачу «в лоб», применяя функцию приведения типов прямо в тексте запроса. Схема выглядит следующим образом:


ПО ВЫРАЗИТЬ(ДанныеДокумента.УникальныйИдентификаторУслуги КАК Строка(36)) = ПродажиОбороты.УникальныйИдентификаторУслуги

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

На уровне СУБД (например, MS SQL Server или PostgreSQL) типы данных УникальныйИдентификатор и Строка хранятся принципиально по-разному. Идентификатор хранится в виде компактного 16-байтового бинарного значения, тогда как строка длиной 36 символов занимает в разы больше места в юникоде. Платформа 1С не умеет на лету транслировать преобразование бинарного формата в строку внутри SQL-запроса, так как это привело бы к колоссальному падению производительности и невозможности использования индексов СУБД при соединении таблиц.

Способ 1. Архитектурно правильный — использование Справочника

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

Вместо записи УИД в регистры создайте новый справочник (например, Справочник.УникальныеУслуги). При первом обращении/заказе услуги программно создавайте элемент этого справочника, где в качестве кода или наименования пишите ваш GUID (или даже генерируйте стандартную ссылку 1С). Во всех документах и регистрах в качестве типа реквизитов и измерений используйте СправочникСсылка.УникальныеУслуги.

Преимущества этого подхода:

  1. Полное соответствие объектной парадигме 1С.
  2. Максимально быстрое соединение таблиц в запросах по ссылочному типу (индексы СУБД будут работать идеально).
  3. Возможность в будущем легко добавить новые реквизиты к этой «услуге» без переделки структуры регистров.

Способ 2. Обходной путь через Таблицу Значений во временном коде

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

Рассмотрим по шагам данный алгоритм:

  1. Получаем данные исходного документа (где УИД хранится как тип УникальныйИдентификатор) обычным запросом и выгружаем результат в ТаблицуЗначений.
  2. Добавляем в эту таблицу новую колонку с типом Строка(36).
  3. Обходим таблицу в цикле и заполняем новую строковую колонку строковым представлением УИД.
  4. Передаем модифицированную таблицу обратно в запрос в качестве параметра, помещаем ее во временную таблицу (ВТ) и выполняем соединение со вторым источником уже по строковому полю.

Посмотрим на пример реализации в коде:


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

Запрос1.УстановитьПараметр("Ссылка", ДокументСсылка);
ТаблицаДанных = Запрос1.Выполнить().Выгрузить();

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

// Шаг 3: Приводим типы в коде 1С
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
    СтрокаТЗ.УИД_Строка = Строка(СтрокаТЗ.УИД_Исходный);
КонецЦикла;

// Шаг 4: Передаем ТЗ во второй запрос и соединяем с регистром накопления
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

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

Запрос2.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);
Запрос2.Выполнить();

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

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

Способ 3. Компромиссное решение — дублирование реквизита (кэширование)

Если соединение по УИД требуется выполнять очень часто в тяжелых отчетах, где выгрузка во временные таблицы критично снижает производительность, можно применить «костыль оптимизации» — дублирование данных.

Для этого выполним следующие действия:

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

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

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

Важное замечание для платформы версии 8.3.22 и выше

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


ВЫБРАТЬ
    УникальныйИдентификатор(Номенклатура.Ссылка) КАК УИД_Номенклатуры
ИЗ
    Справочник.Номенклатура КАК Номенклатура

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

← На главную