При работе с базами данных 1С:Предприятие на уровне SQL-запросов разработчики часто сталкиваются с тем, что данные выглядят «нечитаемыми». Особенно это касается ссылочных полей, таких как _IDRRef. В этой статье мы подробно разберем, в каких кодировках 1С хранит строковые данные, почему ссылки представлены в бинарном виде и как правильно преобразовать их в привычный GUID с помощью SQL и внешних инструментов.
Начнем с базового вопроса кодировок. Разберем ситуацию, когда мы пытаемся понять, как именно текст попадает в таблицы базы данных. В MS SQL Server для баз данных 1С строковые данные всегда хранятся в кодировке Unicode. Рассмотрим подробнее основные технические параметры:
NVARCHAR и NCHAR для хранения текстовой информации. Эти типы используют двухбайтовую кодировку UCS-2 (которая является подмножеством UTF-16). Это позволяет платформе корректно отображать символы любых алфавитов в одном поле.Cyrillic_General_CI_AS.
CI (Case Insensitive) — означает, что поиск и сравнение строк будут регистронезависимыми (буквы "А" и "а" эквивалентны).AS (Accent Sensitive) — означает чувствительность к ударениям.Проанализируем типичную ошибку: если вы видите «кракозябры» при выборке данных через внешние скрипты (например, на PHP или Python), это чаще всего означает, что драйвер подключения пытается интерпретировать Unicode-строку как однобайтовую кодировку (Windows-1251 или UTF-8) без должного декодирования.
Выясним причину, по которой ссылки 1С выглядят как набор странных символов. Рассмотрим поле _IDRRef. Это поле имеет тип binary(16). Оно представляет собой 16-байтовый идентификатор (GUID), который в 1С соответствует уникальной ссылке на объект.
Многие начинающие разработчики пытаются прочитать это поле как обычную строку, получая результат вида „Ќј®Е6љ6.... Это происходит потому, что любая программа пытается отобразить «сырые» байты через текущую кодовую таблицу. На самом деле, это не текст, а шестнадцатеричное число.
Самый важный и сложный момент при работе с _IDRRef — это так называемое «перемешивание байтов». Проанализируем ситуацию: 1С хранит GUID в SQL-базе не в том порядке, в котором мы видим его в программном коде String(Ссылка.УникальныйИдентификатор()).
Зачем это нужно? 1С оптимизирует работу индексов MS SQL Server. В стандартном GUID (RFC 4122) младшие байты, которые меняются чаще всего, стоят в начале. Если записывать их в индекс «как есть», это приведет к сильной фрагментации индекса при добавлении новых записей. 1С переносит эти «динамичные» байты в конец, превращая случайную вставку в последовательную. Это значительно повышает производительность дисковой подсистемы.
Рассмотрим схему трансформации байтов. Если мы имеем стандартный GUID, разбитый на группы: 1-2-3-4-5, то в SQL поле _IDRRef он будет храниться в порядке: 4-5-3-2-1. Точнее, последние 8 байт перемещаются в начало, а первые блоки байтов — в конец и частично инвертируются.
Если нам нужно получить читаемую строку идентификатора прямо в консоли SQL Management Studio или через PHP, мы можем воспользоваться функцией CONVERT. Разберем пример запроса:
SELECT
TOP 10
_Description,
CONVERT(NVARCHAR(MAX), _IDRRef, 2) AS GUID_As_Hex
FROM
_Reference10; -- Пример таблицы справочника
В данном примере параметр 2 в функции CONVERT указывает SQL-серверу преобразовать бинарные данные в шестнадцатеричную строку без префикса 0x. Полученная строка всё еще будет иметь «перепутанный» порядок байтов 1С, но её уже можно использовать для поиска или программной обработки.
Разберем, как выглядит алгоритм «сборки» нормального идентификатора из массива байтов, полученного из SQL. Рассмотрим пример кода, который выполняет обратную перестановку:
// Предположим, А - это массив байтов (binary), полученный из SQL
// Создадим таблицу соответствия шестнадцатеричных значений
Ч16 = Новый Массив(256);
Символы16 = "0123456789abcdef";
Для Сч = 0 По 255 Цикл
Ч16[Сч] = Сред(Символы16, Цел(Сч / 16) + 1, 1) + Сред(Символы16, Сч % 16 + 1, 1);
КонецЦикла;
// Собираем строку GUID в формате RFC 4122, переставляя индексы
// 1С хранит: 0-7 байты (стандартные 8-15), 8-15 байты (стандартные 0-7 в обратном порядке)
Результат = Ч16[А[12]] + Ч16[А[13]] + Ч16[А[14]] + Ч16[А[15]] + "-" +
Ч16[А[10]] + Ч16[А[11]] + "-" +
Ч16[А[8]] + Ч16[А[9]] + "-" +
Ч16[А[0]] + Ч16[А[1]] + "-" +
Ч16[А[2]] + Ч16[А[3]] + Ч16[А[4]] + Ч16[А[5]] + Ч16[А[6]] + Ч16[А[7]];
Этот код наглядно показывает, какие именно байты нужно поменять местами, чтобы сопоставить данные в SQL-таблице с конкретным объектом в интерфейсе 1С.
Выясним, как избежать проблем при работе с бинарными данными в PHP. Если вы используете драйвер sqlsrv, важно помнить, что по умолчанию он может пытаться привести binary(16) к строке, что приведет к потере данных. Рекомендуется использовать параметры привязки типов:
SQLSRV_ENC_BINARY для получения «сырого» потока байтов.bin2hex() для перевода полученного результата в строку.Посмотрим на ситуацию с точки зрения архитектуры. В обсуждении упоминалось использование веб-сервисов как альтернативы прямым запросам. Разберем плюсы и минусы обоих подходов:
Прямые SQL-запросы:
Веб-сервисы (REST/SOAP):
Проанализировав всё вышесказанное, можно сделать вывод: если ваша задача — быстрая интеграция или построение сложных отчетов на внешних системах, использование CONVERT и понимание структуры _IDRRef являются необходимыми навыками. Если же важна надежность и простота — лучше использовать штатные механизмы 1С.