Как соединить данные таблиц 1С в прямых SQL-запросах и преобразовать бинарные ссылки в GUID

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

Работа с базой данных 1С напрямую через SQL-запросы (например, через ADO) — это мощный инструмент для интеграции систем или быстрого извлечения больших объемов данных. Однако этот метод сопряжен с рядом сложностей: от поиска имен таблиц в метаданных до обработки специфических типов данных 1С, таких как binary(16). В этой статье мы подробно разберем, как правильно соединять таблицы документов, справочников и их табличных частей, а также научимся преобразовывать «сырые» бинарные данные в привычные нам уникальные идентификаторы (GUID).

Понимание структуры таблиц в MS SQL Server для 1С

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

Прежде чем писать запрос, нам необходимо разобраться, как 1С хранит данные на уровне СУБД. Платформа 1С:Предприятие не использует человекочитаемые названия таблиц, такие как «Документ.ЗаказПоставщику». Вместо этого она генерирует технические имена: _Document30, _Reference25 и так далее. Цифры в названиях зависят от конкретной конфигурации и могут меняться при реструктуризации базы.

Рассмотрим основные правила именования (для глубокого изучения можно использовать анализ структуры метаданных):

  1. _DocumentN — основные данные документа (шапка).
  2. _DocumentN_VT_M — табличная часть документа.
  3. _ReferenceN — данные справочника.
  4. _IDRRef — уникальный идентификатор записи (ссылка).
  5. _FldN — реквизиты объекта.

Проанализируем типичную задачу: нам нужно получить список номенклатуры из табличной части документа и поставщика из его шапки. Для этого нам потребуется выполнить INNER JOIN между тремя таблицами: шапкой документа, его табличной частью и справочником поставщиков.

Реализация соединения таблиц через SQL

Допустим, наша шапка документа — это _Document30, табличная часть — _Document30_VT111, а справочник поставщиков — _Reference25. Связь между шапкой и табличной частью осуществляется по полю _Document30_IDRRef в табличной части, которое должно быть равно _IDRRef в основной таблице.

Разберем пример кода SQL-запроса:


SELECT 
    Doc._Date_Time AS Дата,
    Doc._Number AS Номер,
    Vend._Description AS Поставщик,
    Items._Fld555 AS НоменклатураНаименование -- Пример поля номенклатуры
FROM 
    [1c_SKLAD].[dbo].[_Document30] AS Doc
INNER JOIN 
    [1c_SKLAD].[dbo].[_Document30_VT111] AS Items ON Doc._IDRRef = Items._Document30_IDRRef
LEFT JOIN 
    [1c_SKLAD].[dbo].[_Reference25] AS Vend ON Doc._Fld49RRef = Vend._IDRRef

В данном запросе мы используем LEFT JOIN для поставщика, чтобы не потерять строки документа, если поставщик вдруг не заполнен. Обратите внимание, что реквизит шапки «Поставщик» в SQL называется _Fld49RRef. Суффикс RRef указывает на то, что это поле является ссылкой.

Проблема бинарных данных: почему мы видим ComAsArray

Когда вы выполняете запрос через ADO в среде 1С и пытаетесь прочитать значение поля _IDRRef или любого поля с суффиксом RRef, вы сталкиваетесь с тем, что вместо привычной строки или ссылки 1С возвращает объект типа COMSafeArray (или ComAsArray). Это происходит потому, что ссылки в SQL хранятся в формате binary(16).

Попытка выполнить Сообщить(Строка(Выборка.Fields("_Fld49RRef").Value)) не даст результата, так как 1С не умеет автоматически приводить массив байтов к ссылочному типу или строковому представлению GUID. Нам нужно выполнить обратное преобразование вручную.

Решение 1: Преобразование Binary в GUID на стороне 1С

Рассмотрим наиболее производительный способ конвертации массива байтов в строковый идентификатор на встроенном языке 1С. Для этого мы создадим массив-кеш для перевода чисел в шестнадцатеричную систему (Hex) и сопоставим индексы байтов. Важно помнить, что 1С хранит байты GUID в специфическом порядке, отличном от стандартного представления в SQL Server.

Выясним правильный порядок байтов и реализуем функцию:


// Предварительно подготовим массив для быстрого конвертирования байтов в HEX
Перем ByteToHex;

Процедура ИнициализироватьКэшHex()
    ByteToHex = Новый Массив(256);
    Символы16 = "0123456789abcdef";
    Для Сч = 0 По 255 Цикл
        ByteToHex[Сч] = Сред(Символы16, Цел(Сч / 16) + 1, 1) + Сред(Символы16, Сч % 16 + 1, 1);
    КонецЦикла;
КонецПроцедуры

Функция ПреобразоватьBinaryVUID(МассивБайтов)
    // Порядок индексов критически важен для соответствия УИД 1С
    СтрокаУИД = ByteToHex[МассивБайтов[12]] + ByteToHex[МассивБайтов[13]] + 
                ByteToHex[МассивБайтов[14]] + ByteToHex[МассивБайтов[15]] + "-" + 
                ByteToHex[МассивБайтов[10]] + ByteToHex[МассивБайтов[11]] + "-" + 
                ByteToHex[МассивБайтов[8]] + ByteToHex[МассивБайтов[9]] + "-" + 
                ByteToHex[МассивБайтов[0]] + ByteToHex[МассивБайтов[1]] + "-" + 
                ByteToHex[МассивБайтов[2]] + ByteToHex[МассивБайтов[3]] + 
                ByteToHex[МассивБайтов[4]] + ByteToHex[МассивБайтов[5]] + 
                ByteToHex[МассивБайтов[6]] + ByteToHex[МассивБайтов[7]];
    
    Возврат СтрокаУИД;
КонецФункции

Проанализируем этот код: мы берем 16 байт из COMSafeArray и склеиваем их в строку с разделителями. После этого полученную строку можно легко превратить в объект УникальныйИдентификатор командой Новый УникальныйИдентификатор(СтрокаУИД).

Решение 2: Преобразование Binary в строку на стороне SQL

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

Посмотрим на пример создания такой функции в MS SQL Server:


CREATE FUNCTION [dbo].[fn_Get1CGUID] (@id binary(16)) 
RETURNS CHAR(36) 
AS 
BEGIN 
    DECLARE @unidentifier CHAR(36) 
    DECLARE @res CHAR(36) 
    
    SET @unidentifier = CONVERT(CHAR(36), CAST(@id AS UNIQUEIDENTIFIER)) 
    
    -- Перестановка частей согласно алгоритму 1С
    SET @res = RIGHT(@unidentifier, 8) + '-' + 
               SUBSTRING(@unidentifier, 20, 4) + '-' + 
               SUBSTRING(@unidentifier, 25, 4) + '-' + 
               SUBSTRING(@unidentifier, 1, 4) + '-' + 
               SUBSTRING(@unidentifier, 5, 12)
               
    RETURN LOWER(@res) 
END;

Используя эту функцию в SELECT, вы получите колонку со строковым GUID, которую ADO прочитает как обычный текст.

Особенности работы с составными типами данных

Рассмотрим ситуацию, когда поле (например, «Поставщик») имеет составной тип данных. В этом случае 1С создает в таблице SQL несколько колонок вместо одной:

Если вы делаете прямой запрос к полю составного типа, обязательно проверяйте _TYPE. Если вы попытаетесь сделать JOIN только по RRef, не учитывая TRef, вы можете ошибочно соединиться с другой таблицей, имеющей запись с таким же бинарным идентификатором (хотя вероятность коллизии GUID мала, логически это будет неверно).

Альтернативные методы доступа к данным

Несмотря на высокую скорость прямых SQL-запросов, они считаются «небезопасными» с точки зрения архитектуры 1С, так как обходят объектную модель и контроль прав доступа (RLS). Разберем альтернативы:

1. COM-соединение (V83.ComConnector): Вы работаете с объектами 1С как обычно, используя НайтиПоНаименованию() или язык запросов 1С. Это медленнее из-за инициализации окружения, но надежнее.

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

3. Web-сервисы и OData: Если вам нужно передать данные в другую базу 1С, лучше поднять HTTP-сервис, который будет отдавать JSON. Это современный стандарт, не зависящий от драйверов ADO и архитектуры БД.

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

Мы выяснили, что соединение данных в таблицах 1С через SQL требует понимания внутренней структуры хранения ссылок. Использование INNER JOIN по полям _IDRRef и _Fld...RRef позволяет быстро выбирать данные. Основная сложность с binary(16) решается либо на стороне 1С через побайтовую конвертацию в Hex-строку, либо на стороне SQL через специальную функцию перестановки байтов. Выбирайте тот метод, который лучше подходит под ваши ограничения по производительности и доступным правам на сервере.

← На главную