Как сделать связь в запросе 1С по части ячейки данных из внешнего источника Bitrix24

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

При интеграции 1С:Предприятие 8.3 с внешними базами данных (например, MySQL, используемой в коробочной версии Bitrix24) разработчики часто сталкиваются с проблемой: данные в таблицах источника хранятся в формате, неудобном для прямой связи. Типичный пример — поле UF_DEPARTMENT, которое содержит сериализованный PHP-массив вида a:1:{i:0;i:311;}. В этой статье мы разберем, как извлечь нужный идентификатор (например, "311") и использовать его для соединения таблиц в запросе, а также проанализируем причины возникающих при этом ошибок.

Разбор структуры данных и первичная постановка задачи

В базе данных Bitrix24 информация о принадлежности сотрудника к отделам хранится в таблице b_uts_user. Значение поля UF_DEPARTMENT представляет собой строку, где зашифрован массив ID отделов. Если сотрудник состоит в одном отделе с ID 311, строка выглядит как a:1:{i:0;i:311;}. Наша задача — связать эту таблицу с таблицей структуры отделов b_uts_iblock_5_section по полю VALUE_ID.

Проблема: Платформа 1С не имеет встроенных средств для десериализации PHP-массивов внутри SQL-запроса. Нам приходится использовать строковые функции языка запросов для "вырезания" нужной подстроки.

Анализ ошибок при использовании ВЫРАЗИТЬ и строковых функций

Рассмотрим попытку автора решить задачу "в лоб" через функции ПОДСТРОКА и СтрЗаменить. Типичный код, вызывающий ошибку:


| ЛЕВОЕ СОЕДИНЕНИЕ ВнешнийИсточникДанных.Битрикс.Таблица.b_uts_iblock_5_section КАК b_uts_iblock_5_section
| ПО ВЫРАЗИТЬ(СтрЗаменить(ПОДСТРОКА(b_uts_user.UF_DEPARTMENT,12,3),";","") КАК Число(3)) = b_uts_iblock_5_section.VALUE_ID

Здесь возникают сразу две критические проблемы:

  1. Несовместимые типы в ВЫРАЗИТЬ: В языке запросов 1С оператор ВЫРАЗИТЬ не является аналогом CAST или CONVERT в SQL. Он не может преобразовать строку "311" в число. ВЫРАЗИТЬ предназначен только для приведения составного типа к определенному или для ограничения длины строки/точности числа.
  2. Ошибка ODBC и права доступа: Ошибка execute command denied... for routine 'dbalupro.REGEXP_REPLACE' указывает на то, что при трансляции запроса 1С пытается использовать в MySQL функцию регулярных выражений. Однако у пользователя БД, под которым выполняется подключение, нет прав EXECUTE на выполнение системных процедур или функций в MySQL.

Вариант 1: Работа через строковое сравнение (с учетом версии платформы)

Если мы работаем на версии платформы ниже 8.3.20, мы ограничены в преобразовании типов. В этом случае единственным способом связать данные в одном запросе является приведение обеих сторон сравнения к строке. Разберем, как это реализовать:

Проанализируем выражение для очистки строки. Нам нужно избавиться от лишних символов (;, }) и дополнить строку нулями для корректного сравнения, если это необходимо. Однако, правильнее будет просто выделить подстроку:


| ЛЕВОЕ СОЕДИНЕНИЕ ВнешнийИсточникДанных.Битрикс.Таблица.b_uts_iblock_5_section КАК b_uts_iblock_5_section
| ПО ВЫРАЗИТЬ(Прав("000" + СтрЗаменить(СтрЗаменить(ПОДСТРОКА(b_uts_user.UF_DEPARTMENT, 12, 3), ";", ""), "}", ""), 3) КАК СТРОКА(5)) 
|    = ВЫРАЗИТЬ(b_uts_iblock_5_section.VALUE_ID КАК СТРОКА(5))

Важно: Такой подход крайне непроизводителен. MySQL не сможет использовать индексы при связи по функции, что приведет к полному сканированию таблиц (Full Table Scan). Если в базе данных десятки тысяч задач, отчет будет работать очень медленно.

Вариант 2: Использование временных таблиц (Рекомендуемый метод)

Чтобы избежать проблем с производительностью и сложным синтаксисом внешних источников, рассмотрим более надежный архитектурный подход. Мы можем разделить получение данных на этапы:

  1. Выгрузим во временную таблицу только нужные нам данные из b_uts_user (ссылку на пользователя и строку UF_DEPARTMENT).
  2. В коде 1С обработаем эту таблицу значений, программно вычислив ID отдела.
  3. Передадим готовую таблицу с уже готовыми числами обратно в запрос.

Пример программной обработки:


// Получаем данные из внешнего источника
Запрос = Новый Запрос("ВЫБРАТЬ VALUE_ID, UF_DEPARTMENT ИЗ ВнешнийИсточникДанных.Битрикс.Таблица.b_uts_user");
ТЗ_Пользователи = Запрос.Выполнить().Выгрузить();

// Добавляем колонку для чистого ID отдела
ТЗ_Пользователи.Колонки.Добавить("ЧистыйIDОтдела", Новый ОписаниеТипов("Число"));

Для Каждого СтрокаТЗ Из ТЗ_Пользователи Цикл
    // Простая логика парсинга "a:1:{i:0;i:311;}"
    ПозНачала = Найти(СтрокаТЗ.UF_DEPARTMENT, "i:0;i:");
    Если ПозНачала > 0 Тогда
        ЧастьСтроки = Сред(СтрокаТЗ.UF_DEPARTMENT, ПозНачала + 7);
        ПозКонца = Найти(ЧастьСтроки, ";");
        СтрокаID = Лев(ЧастьСтроки, ПозКонца - 1);
        СтрокаТЗ.ЧистыйIDОтдела = Число(СтрокаID);
    КонецЕсли;
КонецЦикла;

После такой обработки мы можем поместить ТЗ_Пользователи во временную таблицу и легко связать её с остальными данными запроса по числовому полю ЧистыйIDОтдела.

Вариант 3: Создание View (Представления) на стороне MySQL

Если у вас есть доступ к управлению базой данных MySQL, проанализируем возможность создания VIEW. Это позволит "вынести" сложную логику парсинга на сторону сервера БД. В MySQL можно использовать функции SUBSTRING_INDEX для извлечения ID.

Пример SQL-кода для создания представления:


CREATE VIEW v_user_departments AS
SELECT 
    VALUE_ID, 
    CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(UF_DEPARTMENT, ';', -2), ':', -1) AS UNSIGNED) as DEPARTMENT_ID
FROM b_uts_user;

После создания такого VIEW, мы подключаем его в 1С как новую таблицу внешнего источника данных. Теперь в запросе нам доступно чистое числовое поле DEPARTMENT_ID, и связь будет выглядеть максимально просто и быстро.

Решение проблемы с группировкой

Выясним причину ошибки Поле не входит в группу. В 1С, если вы используете СГРУППИРОВАТЬ ПО, все поля, перечисленные в ВЫБРАТЬ, которые не являются агрегатными функциями (СУММА, МАКСИМУМ и т.д.), должны быть в точности продублированы в блоке группировки.

Если вы используете сложные выражения в ВЫБРАТЬ, например:


ВЫБРАТЬ
    ВЫРАЗИТЬ(Прав(b_uts_user.UF_DEPARTMENT, 3) КАК СТРОКА(3)) КАК Отдел
...
СГРУППИРОВАТЬ ПО
    ВЫРАЗИТЬ(Прав(b_uts_user.UF_DEPARTMENT, 3) КАК СТРОКА(3))

Рассмотрим лучший способ: вынести расчетные поля во вложенный запрос, а во внешнем запросе делать группировку по их псевдонимам. Это сделает код чище и избавит от ошибок компоновки.

Резюме и рекомендации

Подводя итог нашему разбору, можно выделить следующие правила работы с "грязными" данными во внешних источниках:

  1. Не используйте ВЫРАЗИТЬ для конвертации типов: Помните, что в 1С это не работает как CAST.
  2. Проверяйте права пользователя MySQL: Если 1С выдает ошибку на REGEXP_REPLACE, запросите у администратора БД права EXECUTE.
  3. Предпочитайте временные таблицы: Это самый стабильный способ обработки данных, которые нельзя связать напрямую.
  4. Оптимизируйте на стороне источника: Если данных много, создание VIEW в MySQL — единственный способ обеспечить приемлемую скорость работы отчета.

Используя эти методы, мы сможем эффективно интегрировать данные Bitrix24 в учетную систему 1С, несмотря на специфику хранения PHP-сериализованных массивов.

← На главную