При интеграции систем или анализе сетевых журналов разработчики нередко сталкиваются с ситуацией, когда в одной таблице IP-адрес хранится в виде привычной строки с точками (например, 192.168.0.1), а во второй — представлен числом или строкой без разделителей. Попытка выполнить соединение таких таблиц напрямую в тексте запроса приводит к ошибкам несовместимости типов или к неверным результатам выборки. Разберем особенности работы языка запросов 1С, выясним причину ограничений и рассмотрим надежные способы решения этой задачи.
Проанализируем, почему решить данную задачу одной лишь инструкцией ВЫРАЗИТЬ внутри запроса невозможно:
ВЫРАЗИТЬ(Поле КАК Тип) в языке запросов платформы 1С:Предприятие предназначена исключительно для сужения составных типов ссылочных данных или для ограничения максимальной длины строковых полей. Преобразовать Число в Строку или наоборот с помощью этой функции нельзя.СтрНайти), регулярные выражения и функции разделения строк. Из-за этого распарсить строку вида 192.168.0.1 на отдельные октеты непосредственно в теле запроса невозможно.Прежде чем выполнять сопоставление, важно понять, как именно числовое значение сформировано в исходной базе:
192.168.0.1 превращается в 192.168.000.001, а в числовом виде — 192168000001). Пробелы между группами цифр при отображении в 1С чаще всего являются визуальным форматированием разделителя групп разрядов.19216801), восстановить исходный адрес однозначно невозможно, так как возникает коллизия: число 1921681122 может означать как 192.168.1.122, так и 192.168.11.22.A * 256^3 + B * 256^2 + C * 256 + D, занимающий до 10 знаков (от 0 до 4 294 967 295).Наиболее надежный и универсальный метод — выгрузить одну из таблиц в память, программно привести ключ сопоставления к единому формату и передать обработанную таблицу значений в запрос в виде параметра.
Рассмотрим по шагам алгоритм, при котором строковые 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Символов)";
Запрос.УстановитьПараметр("ТаблицаНормализованная", ТаблицаНормализованная);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Если во второй таблице IP-адрес хранится как Число(12, 0), то при чтении платформой 1С число форматируется с разделителями групп. Чтобы сопоставить его со строкой, необходимо преобразовать число во встроенном языке с отключением группировки:
// Преобразуем число 192168000001 в строку "192168000001" без неразрывных пробелов
СтрокаБезПробелов = Формат(ЧисловойIP, "ЧГ=0");
Этот параметр ЧГ=0 гарантирует, что в строку не попадут неразрывные пробелы (Символы.НПП), которые препятствуют корректному сопоставлению строк.
Чтобы избежать регулярных накладных расходов на конвертацию данных при выполнении запросов, рекомендуется придерживаться следующих правил проектирования структур данных:
Строка(15) для стандартной записи с точками или Строка(12) для нормализованного вида с ведущими нулями.НормализованныйIP) и заполняйте его один раз в событии ПередЗаписью. Это позволит выполнять простые и быстрые соединения без предварительной обработки таблиц в памяти.