Как получить физический ID элемента справочника из базы данных SQL?

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

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

Различие между UUID 1С и физическим идентификатором базы данных

Прежде всего, проанализируем ситуацию: в 1С УникальныйИдентификатор представлен в виде строки формата XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Однако в SQL-сервере этот же идентификатор хранится в поле _IDRRef как тип данных binary(16). Самое важное — порядок байтов в этих двух представлениях различается.

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

Рассмотрим алгоритм преобразования UUID в IDRRef

Для того чтобы получить значение, которое можно использовать в прямом SQL-запросе, нам необходимо выполнить побайтовую перестановку. Разделим стандартный UUID на пять групп: {1}-{2}-{3}-{4}-{5}. Порядок байтов в 1С (UUID) и в SQL (_IDRRef) будет соотноситься следующим образом:

  1. Группа 4 и 5 переходят в начало бинарного значения.
  2. За ними следуют группы 3, 2 и 1 в обратном порядке или со специфическим смещением.

Если говорить точнее, то в 1С УникальныйИдентификатор версии 4 генерируется на основе времени, и именно временные составляющие перемещаются в начало для «последовательности» значений в SQL-индексе.

Метод 1: Использование системной функции ЗначениеВСтрокуВнутр

Самый быстрый способ увидеть «внутреннее» представление ссылки внутри кода 1С — это использование функции ЗначениеВСтрокуВнутр(). Разберем на примере:


// Получаем ссылку на элемент справочника
СсылкаНаЭлемент = Справочники.Номенклатура.НайтиПоНаименованию("Товар 1");

// Получаем внутреннее представление
ВнутренняяСтрока = ЗначениеВСтрокуВнутр(СсылкаНаЭлемент);
// Результат будет иметь вид: {"#",88261b80-3601-11e5-80c1-00155d013e01,{-1,00000000000000000000000000000000}}

В этой строке содержится 32-символьный шестнадцатеричный код. Это значение максимально близко к тому, что лежит в поле _IDRRef, но оно все равно может требовать перестановки блоков, если вы планируете использовать его в WHERE фильтрах SQL-запросов через внешние источники данных.

Метод 2: Программное получение binary-значения для SQL

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


Функция ПолучитьIDДляSQL(Ссылка)
    
    // Получаем UUID из ссылки
    УИД = Строка(Ссылка.УникальныйИдентификатор());
    // Убираем дефисы
    Стр = СтрЗаменить(УИД, "-", "");
    
    // Выполняем перестановку групп байтов (инверсия для SQL)
    // Формат в SQL: Группа4 + Группа5 + Группа3 + Группа2 + Группа1
    // (Это упрощенная схема, реальный порядок зависит от версии платформы)
    
    Результат = Сред(Стр, 17, 4) + Сред(Стр, 21, 12) + Сред(Стр, 13, 4) + Сред(Стр, 9, 4) + Лев(Стр, 8);
    
    Возврат "0x" + Результат;
    
КонецФункции

Важный момент: Данный метод возвращает строковое представление бинарного кода, которое SQL сервер воспримет как идентификатор при использовании префикса 0x.

Как найти нужную таблицу в базе данных?

Чтобы понять, в какой именно таблице искать поле _IDRRef, нам нужно сопоставить имя объекта в конфигураторе (например, Справочник.Контрагенты) с именем таблицы в СУБД (например, _Reference45). Для этого выясним структуру хранения базы данных.

Воспользуемся встроенным методом платформы:


// Получаем структуру хранения всех таблиц
СтруктураХранения = ПолучитьСтруктуруХраненияБазыДанных();

// Можно отфильтровать по конкретному объекту
МассивИмен = Новый Массив;
МассивИмен.Добавить("Справочник.Номенклатура");
СтруктураОбъекта = ПолучитьСтруктуруХраненияБазыДанных(МассивИмен);

Для Каждого СтрокаТаблицы Из СтруктураОбъекта Цикл
    Сообщить("Имя таблицы в БД: " + СтрокаТаблицы.ИмяТаблицыХранения);
КонецЦикла;

Теперь, зная имя таблицы и имея алгоритм преобразования идентификатора, мы можем выполнить прямой запрос к СУБД:


-- Пример запроса в SQL Management Studio
SELECT * FROM _Reference45 WHERE _IDRRef = 0x80C100155D013E0111E5360188261B80

Подведем итоги

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

  1. Идентификатор в 1С и в SQL — это одни и те же байты, но в разном порядке.
  2. Для простого просмотра можно использовать ЗначениеВСтрокуВнутр().
  3. Для интеграции на уровне SQL необходимо выполнять инверсию (перестановку) байтов GUID.
  4. Для определения целевой таблицы всегда следует использовать метод ПолучитьСтруктуруХраненияБазыДанных(), так как имена таблиц могут меняться при реструктуризации (например, при удалении и добавлении объектов).

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

← На главную