Как извлечь и распаковать данные типа ХранилищеЗначения напрямую из SQL Server

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

При прямой интеграции с базой данных 1С на уровне СУБД часто возникает задача прочитать данные из таблиц, где реквизиты имеют тип ХранилищеЗначения. В физической структуре MS SQL Server такие поля имеют тип varbinary(max). Попытка выполнить стандартное приведение типов с помощью CAST или CONVERT к строковому представлению возвращает набор нечитаемых символов или шестнадцатеричный дамп.

Разберем подробно, как платформа 1С сохраняет бинарные объекты в базе данных, почему обычное преобразование в SQL не работает и какими способами можно получить исходное значение.

Почему прямой CAST в SQL возвращает нечитаемые символы

Проанализируем ситуацию на примере выполнения SQL-запроса к таблице регистра сведений:


DECLARE @b VARBINARY(MAX);
SET @b = 0x0201534B6FF4888DC14EA0D5EBB6BDA0...;
SELECT CAST(@b AS VARCHAR(MAX));

В результате такого преобразования возвращается не исходная строка или XML-структура, а бинарная «каша». Причина заключается в том, что платформа 1С перед сохранением данных в ХранилищеЗначения упаковывает их с использованием алгоритма сжатия (Deflate/zlib).

Рассмотрим структуру бинарного блока, хранящегося в поле varbinary(max):

  1. Служебный заголовок платформы: первый байт или сигнатура определяют режим хранения. Например, байт 0x02 указывает на то, что полезная нагрузка упакована алгоритмом сжатия Deflate. Байт 0x01 обозначает хранение данных без сжатия.
  2. Сжатый поток данных: тело объекта запаковано по алгоритму Deflate (raw Deflate без стандартных заголовков контейнера GZIP).
  3. Сериализованные данные 1С: после распаковки поток представляет собой внутреннюю сериализацию объекта 1С, текст в кодировке UTF-8/UTF-16 или сериализованный XML/XDTO-пакет.

Встроенная функция MS SQL Server DECOMPRESS() (доступная с SQL Server 2016) не может распаковать эти данные «из коробки», так как ожидает стандартный заголовок RFC 1952 (GZIP), которого в структуре 1С нет.

Способ 1. Распаковка через SQL CLR (C# в MS SQL Server)

Если необходимо выполнять чтение и распаковку непосредственно на стороне СУБД в рамках хранимых процедур или представлений, эффективным решением является написание пользовательской CLR-функции на C#.

Разберем логику работы такой функции по шагам:

  1. Принимаем входной параметр типа SqlBytes (бинарные данные из поля varbinary(max)).
  2. Проверяем первый байт: если данные сжаты (флаг 0x02), отсекаем байты служебного заголовка платформы (смещение обычно составляет 1–2 байта).
  3. Передаем оставшийся поток в поток распаковки DeflateStream в режиме декомпрессии.
  4. Считываем распакованный массив байтов и декодируем его в строку NVARCHAR(MAX) с использованием кодировки UTF-8.

Способ 2. Извлечение и распаковка внешними скриптами (Python / C# / ETL)

Если данные извлекаются во внешнюю систему через коннекторы ADO, ODBC или специализированные ETL-пайплайны, распаковку проще выполнять на стороне клиентского приложения.

Посмотрим на пример логики на языке Python с использованием библиотеки zlib:


import zlib

def decompress_1c_blob(raw_data: bytes) -> str:
    # Проверяем наличие флага сжатия 1С
    if raw_data[0] == 2:
        # Отсекаем заголовок и передаем raw deflate поток
        decompressed = zlib.decompress(raw_data[2:], -zlib.MAX_WBITS)
    else:
        decompressed = raw_data[1:]
    
    return decompressed.decode('utf-8', errors='ignore')

Использование параметра -zlib.MAX_WBITS указывает библиотеке на отсутствие стандартных заголовков zlib/gzip, что позволяет успешно восстановить полезную нагрузку 1С.

Способ 3. Использование платформенных инструментов 1С

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

Посмотрим, как извлечь значение из объекта ХранилищеЗначения средствами языка 1С:


Хранилище = Выборка.Строения; // Поле типа ХранилищеЗначения
Если Хранилище <> Неопределено Тогда
    ИсходныеДанные = Хранилище.Получить();
    // ИсходныеДанные содержат строку, структуру или двоичные данные в исходном виде
КонецЕсли;

Архитектурные альтернативы прямому чтению из SQL

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

  1. HTTP-сервисы 1С: публикация легковесного REST/JSON-сервиса на стороне базы-источника, который возвращает уже распакованные данные по запросу.
  2. Стандартный интерфейс OData: публикация OData-интерфейса базы для доступа к регистрам сведений и справочникам через стандартные REST-запросы.
  3. Единая внешняя база данных: если цель состоит в совместном использовании адресного классификатора (ФИАС / ГАР) несколькими информационными базами, целесообразно загрузить официальные базы ФИАС в отдельную СУБД и подключить их ко всем конфигурациям через механизм ВнешниеИсточникиДанных.
← На главную