При работе с прямыми SQL-запросами к базе данных 1С программисты часто сталкиваются с проблемой: значения ссылок в таблицах (поля типа _IDRRef или _Fld...RRef) хранятся в бинарном формате binary(16). Если попытаться просто прочитать это значение или сравнить его с обычным GUID, полученным в 1С, мы увидим несоответствие. Это происходит из-за специфического алгоритма хранения байтов, который использует платформа 1С для оптимизации работы индексов MS SQL Server. Для сопоставления объектов конфигурации с физическими таблицами и полями СУБД можно использовать отчет по структуре хранения базы данных 1С.
В этой статье мы подробно разберем, как правильно преобразовывать бинарные ссылки в строковые идентификаторы, как подготавливать условия для SQL-запросов и как возвращать полученные данные обратно в объекты 1С. Если объекты в разных информационных базах имеют несовпадающие ссылки, для их сопоставления и миграции используется перенос данных между похожими конфигурациями 1С с поиском по произвольным полям.
Разберем ситуацию: 1С хранит уникальный идентификатор в инвертированном виде. Если представить стандартный UUID как последовательность групп A-B-C-D-E, то в базе данных MS SQL в поле binary(16) он будет записан в порядке D-E-C-B-A. Рассмотрим пример:
Идентификатор в 1С: 89ee7bb0-0fab-e5c7-4f44-96aeffe0c13c
Запись в SQL (hex): 0x4F4496AEFFE0C13CE5C70FAB89EE7BB0
Важный момент: такая перестановка необходима для того, чтобы наиболее часто меняющиеся части идентификатора (которые в 1С-овском GUID версии 1 находятся в конце) оказались в начале бинарного ключа. Это значительно уменьшает фрагментацию индексов в SQL Server при массовом добавлении новых записей.
Если нам нужно получить строковое представление ссылки прямо в результате запроса, мы можем воспользоваться встроенными функциями SQL. Рассмотрим вариант использования CONVERT и системных функций для получения HEX-строки.
Для преобразования бинарного значения в строку в формате 0x... проанализируем следующий пример:
SELECT
[sys].[fn_varbintohexstr](_IDRRef) AS HexUID,
CAST(_IDRRef AS uniqueidentifier) AS SqlGuid
FROM dbo._Reference6035
Однако стоит учитывать, что CAST(... AS uniqueidentifier) вернет «родной» SQL-гуид, который не совпадает визуально с 1С-овским. Чтобы получить именно ту строку, которую выдает 1С, потребуется более сложная логика перестановки подстрок. При анализе реальных запросов из профайлера и сопоставлении их с объектами конфигурации можно воспользоваться инструментом для перевода SQL-запросов в термины метаданных 1С.
Часто задача стоит наоборот: у нас есть ссылка в 1С, и мы хотим найти запись в SQL. Чтобы индекс отработал эффективно, лучше не конвертировать поле таблицы в строку, а преобразовать нашу ссылку в бинарный вид и передать в запрос.
Рассмотрим алгоритм подготовки строкового литерала для SQL-запроса через XMLСтрока:
// Получаем GUID в виде строки через XML-сериализацию
ИдентификаторСтр = XMLСтрока(СсылкаНаОбъект);
// В результате получим строку вида "4f4496ae-ffe0-c13c-e5c7-0fab89ee7bb0"
// Преобразуем ее в формат, понятный SQL (D-E-C-B-A)
// Нам нужно переставить блоки байтов
Блок1 = Сред(ИдентификаторСтр, 1, 8);
Блок2 = Сред(ИдентификаторСтр, 10, 4);
Блок3 = Сред(ИдентификаторСтр, 15, 4);
Блок4 = Сред(ИдентификаторСтр, 20, 4);
Блок5 = Сред(ИдентификаторСтр, 25, 12);
БинарноеЗначение = "0x" + Блок4 + Блок5 + Блок3 + Блок2 + Блок1;
УсловиеЗапроса = "WHERE _IDRRef = " + БинарноеЗначение;
Существует еще один интересный метод, основанный на функции ЗначениеВСтрокуВнутр. Эта функция возвращает шестнадцатеричное представление ссылки в определенной позиции строки. Выясним, как это использовать:
ВнутрСтр = ЗначениеВСтрокуВнутр(СсылкаОбъект);
// Строка имеет вид: {"#",...,"9659:ab2b001b78e134e011dfec0814418025"}
// Где ab2b... — это и есть ссылка в HEX-формате (уже в нужном для SQL порядке)
СсылкаБезСкобки = Сред(ВнутрСтр, СтрДлина(ВнутрСтр) - 32, 32);
IDДляSQL = "0x" + СсылкаБезСкобки;
Этот метод удобен тем, что не требует ручной перестановки байтов, так как платформа сама выдает HEX в «складском» формате для базы данных. Для последующего контроля результата и поиска расхождений в учете после прямого обращения к таблицам БД используется автоматическая сверка бухгалтерских и налоговых проводок между информационными системами.
Если вы получили данные через ADO, поле ссылки вернется в виде массива байтов (SafeArray). Чтобы превратить его обратно в полноценную ссылку 1С, можно использовать следующий подход:
[sys].[fn_varbintohexstr].УникальныйИдентификатор.fn_varbintohexstr.Проанализируем функцию для восстановления правильного порядка байтов на стороне 1С:
Функция ПолучитьУИДИзSQLСтроки(Знач GUID_SQL)
// Убираем префикс 0x
GUID = Прав(GUID_SQL, СтрДлина(GUID_SQL) - 2);
// Переставляем блоки из формата D-E-C-B-A обратно в A-B-C-D-E
// Примерная схема:
УИД = НРег(Прав(GUID, 8) + "-" +
Сред(GUID, 21, 4) + "-" +
Сред(GUID, 17, 4) + "-" +
Лев(GUID, 4) + "-" +
Сред(GUID, 5, 12));
Возврат Новый УникальныйИдентификатор(УИД);
КонецФункции
Затем, имея объект УникальныйИдентификатор, мы легко получаем ссылку нужного нам типа:
СсылкаНаСправочник = Справочники.Номенклатура.ПолучитьСсылку(НовыйУИД);
При обработке десятков тысяч записей через COM-соединение (ADO) вызов строковых функций преобразования в цикле может существенно замедлить работу. Рассмотрим более быстрый способ обработки SafeArray, который возвращает ADODB.Recordset:
Вместо конвертации каждого значения в строку через SQL, мы можем заранее подготовить массив HEX-символов в 1С и обращаться к нему по индексу байта. Это работает на порядок быстрее:
// Предварительно заполняем таблицу соответствия байтов
ТаблицаБайтов = Новый Массив(256);
Символы16 = "0123456789abcdef";
Для Сч = 0 По 255 Цикл
ТаблицаБайтов[Сч] = Сред(Символы16, Цел(Сч / 16) + 1, 1) + Сред(Символы16, Сч % 16 + 1, 1);
КонецЦикла;
// В цикле обхода данных ADO:
Байты = Выборка.Fields("_IDRRef").Value; // Получаем SafeArray
// Собираем строку УИД с учетом перестановки байтов (A-B-C-D-E)
// Индексы байтов в массиве (0-15) соответствуют формату D-E-C-B-A
СтрокаУИД = ТаблицаБайтов[Байты[12]] + ТаблицаБайтов[Байты[13]] + ... // и так далее
Подведем итоги: для работы со ссылками 1С на уровне SQL критически важно понимать разницу в порядке хранения байтов. Самый производительный способ поиска — передача в SQL заранее подготовленного бинарного литерала. Самый простой способ получения ссылки из SQL — использование системных функций конвертации в HEX-строку с последующим восстановлением структуры идентификатора в коде 1С.