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

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

При интеграции систем или анализе сетевых журналов разработчики нередко сталкиваются с ситуацией, когда в одной таблице IP-адрес хранится в виде привычной строки с точками (например, 192.168.0.1), а во второй — представлен числом или строкой без разделителей. Попытка выполнить соединение таких таблиц напрямую в тексте запроса приводит к ошибкам несовместимости типов или к неверным результатам выборки. Разберем особенности работы языка запросов 1С, выясним причину ограничений и рассмотрим надежные способы решения этой задачи.

Ограничения языка запросов 1С при работе с типами данных

Проанализируем, почему решить данную задачу одной лишь инструкцией ВЫРАЗИТЬ внутри запроса невозможно:

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

Особенности числового представления IP-адресов

Прежде чем выполнять сопоставление, важно понять, как именно числовое значение сформировано в исходной базе:

  1. Октеты с ведущими нулями (12 знаков): Классический вариант хранения адреса фиксированной длины — дополнение каждого октета нулями до трех знаков (например, 192.168.0.1 превращается в 192.168.000.001, а в числовом виде — 192168000001). Пробелы между группами цифр при отображении в 1С чаще всего являются визуальным форматированием разделителя групп разрядов.
  2. Число без ведущих нулей: Если адрес был преобразован простым удалением точек (например, 19216801), восстановить исходный адрес однозначно невозможно, так как возникает коллизия: число 1921681122 может означать как 192.168.1.122, так и 192.168.11.22.
  3. 32-битное целое число: В сетевых технологиях стандартным числовым представлением IPv4 является расчет по формуле A * 256^3 + B * 256^2 + C * 256 + D, занимающий до 10 знаков (от 0 до 4 294 967 295).

Способ 1. Предварительная нормализация данных во временной таблице

Наиболее надежный и универсальный метод — выгрузить одну из таблиц в память, программно привести ключ сопоставления к единому формату и передать обработанную таблицу значений в запрос в виде параметра.

Рассмотрим по шагам алгоритм, при котором строковые IP-адреса приводятся к 12-значной строке с ведущими нулями в каждом октете:


// Создаем функцию для нормализации строкового IP-адреса
Функция НормализоватьIP(Знач СтрокаIP)
    
    МассивОктетов = СтрРазделить(СокрЛП(СтрокаIP), ".");
    Если МассивОктетов.Количество() <> 4 Тогда
        Возврат "";
    КонецЕсли;
    
    Результат = "";
    Для Каждого Октет Из МассивОктетов Цикл
        // Дополняем каждый октет нулями до 3 знаков
        ОктетЧисло = Число(Октет);
        ОктетСНулями = Формат(ОктетЧисло, "ЧЦ=3; ЧВН=; ЧГ=0");
        Результат = Результат + ОктетСНулями;
    КонецЦикла;
    
    Возврат Результат;

КонецФункции

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


// Предположим, ТаблицаСоСтроками получена из базы или внешнего источника
ТаблицаНормализованная = Новый ТаблицаЗначений;
ТаблицаНормализованная.Колонки.Добавить("ИсходныйIP", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(15)));
ТаблицаНормализованная.Колонки.Добавить("КлючIP", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(12)));
ТаблицаНормализованная.Колонки.Добавить("Данные");

Для Каждого Стр Из ТаблицаСоСтроками Цикл
    НоваяСтр = ТаблицаНормализованная.Добавить();
    НоваяСтр.ИсходныйIP = Стр.IPАдресСтрока;
    НоваяСтр.Данные = Стр.Данные;
    НоваяСтр.КлючIP = НормализоватьIP(Стр.IPАдресСтрока);
КонецЦикла;

// Передаем таблицу в запрос и связываем по однотипному ключу
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТЗ.ИсходныйIP КАК ИсходныйIP,
    |    ТЗ.КлючIP КАК КлючIP,
    |    ТЗ.Данные КАК ДанныеСтроки
    |ПОМЕСТИТЬ ВТ_СтроковыеДанные
    |ИЗ
    |    &ТаблицаНормализованная КАК ТЗ
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ВТ.ИсходныйIP,
    |    ВТ.ДанныеСтроки,
    |    ТабЧисел.Данные КАК ДанныеЧисла
    |ИЗ
    |    ВТ_СтроковыеДанные КАК ВТ
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВтораяТаблица КАК ТабЧисел
    |        ПО (ВТ.КлючIP = ТабЧисел.IPАдрес12Символов)";

Запрос.УстановитьПараметр("ТаблицаНормализованная", ТаблицаНормализованная);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();

Способ 2. Преобразование числового поля к строке без разделителей

Если во второй таблице IP-адрес хранится как Число(12, 0), то при чтении платформой 1С число форматируется с разделителями групп. Чтобы сопоставить его со строкой, необходимо преобразовать число во встроенном языке с отключением группировки:


// Преобразуем число 192168000001 в строку "192168000001" без неразрывных пробелов
СтрокаБезПробелов = Формат(ЧисловойIP, "ЧГ=0");

Этот параметр ЧГ=0 гарантирует, что в строку не попадут неразрывные пробелы (Символы.НПП), которые препятствуют корректному сопоставлению строк.

Архитектурные рекомендации по хранению IP-адресов

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

  1. Единый стандарт хранения: Не следует хранить идентификаторы, индексы, номера телефонов и IP-адреса в числовом виде, даже если они состоят только из цифр. Оптимальный тип — Строка(15) для стандартной записи с точками или Строка(12) для нормализованного вида с ведущими нулями.
  2. Использование дополнительных реквизитов: Если в системе требуется быстрый поиск или фильтрация по диапазонам, добавьте в объект дополнительный реквизит (например, НормализованныйIP) и заполняйте его один раз в событии ПередЗаписью. Это позволит выполнять простые и быстрые соединения без предварительной обработки таблиц в памяти.
← На главную