Артикул или номер договора хранится строкой: как сравнить его с числом в запросе

· 9 мин

Содержание

Чтобы в запросе 1С сравнить текстовое поле с числом, приведите к строке не поле, а параметр: в коде превратите число в строку через Формат(Число, "ЧГ=0") и сравнивайте строку со строкой. Язык запросов не умеет превращать строку в число через ВЫРАЗИТЬ, поэтому все рабочие способы сводятся к трём: строковый параметр, перевод в число в коде и временная таблица, либо отдельный числовой реквизит в метаданных.

Типичная ситуация: в справочнике «Номенклатура» артикул хранится строкой, а менеджер просит отчёт «все артикулы от 1000 до 2000». Или у договоров есть текстовый реквизит «НомерДоговора», и нужно найти договор номер 125, а в базе он записан как 0125. Запрос, написанный «в лоб», либо ничего не находит, либо сортирует 10 раньше 9.

Почему строка с цифрами в запросе 1С не равна числу

Для платформы "125" и 125 — значения разных типов. Строку она сравнивает посимвольно, слева направо, как слова в словаре. Число сравнивает по величине.

Отсюда три типовых сбоя:

  • 🔹 Пустой результат. Условие ГДЕ Т.Артикул = &Артикул, куда передано число, не находит строку "125". В зависимости от выражения запрос может и вовсе завершиться ошибкой о несовместимых типах.
  • 🔹 Неверный диапазон. Т.Артикул МЕЖДУ "1000" И "2000" захватит "15", "1999999" и "1A": посимвольно они лежат между границами.
  • 🔹 Дубли. "0125", "125" и "125 " с пробелом в конце — три разных значения. В группировке получатся три строки вместо одной.

Источник проблемы почти всегда в метаданных. Разработчик когда-то выбрал тип «Строка», потому что в артикуле иногда бывают буквы или дефис. Или номер договора приходит от контрагента в произвольном виде. Тип поля переделывать долго, поэтому задачу приходится решать в запросе.

Номер документа и код справочника тоже бывают строковыми. Это задаётся свойствами объекта в конфигураторе: «Тип номера» у документа и «Тип кода» у справочника. В типовых конфигурациях они почти всегда строковые, с префиксами.

Как привести текст к числу в запросе 1С и чем заменить ВЫРАЗИТЬ

Первое, что пробует программист, — ВЫРАЗИТЬ(Т.Артикул КАК ЧИСЛО(10, 0)). Не работает : приведение строки к числу язык запросов не поддерживает. Обратное направление, число в строку, тоже недоступно.

Что ВЫРАЗИТЬ умеет на самом деле:

ПриведениеПримерЗачем нужно
Строка неограниченной длины → строка фиксированной длиныВЫРАЗИТЬ(Т.Комментарий КАК СТРОКА(100))Сравнивать, группировать, упорядочивать по длинному тексту
Число → число другой разрядностиВЫРАЗИТЬ(Т.Сумма КАК ЧИСЛО(15, 2))Округлить, задать точность результата
Составной тип → один из его типовВЫРАЗИТЬ(Т.Регистратор КАК Документ.РеализацияТоваровУслуг)Обратиться к реквизитам конкретного типа

Поэтому рабочие способы такие.

Способ 1. Строковый параметр вместо числового

Самый быстрый и безопасный. Число превращается в строку в коде, до выполнения запроса:

НомерИзФормы = 125;

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Договоры.Ссылка,
|	Договоры.НомерДоговора
|ИЗ
|	Справочник.ДоговорыКонтрагентов КАК Договоры
|ГДЕ
|	Договоры.НомерДоговора = &Номер";

Запрос.УстановитьПараметр("Номер", Формат(НомерИзФормы, "ЧГ=0"));

Без ЧГ=0 число 1250 превратится в строку с разделителем групп разрядов — и условие опять ничего не найдёт. Для склейки числа со строкой всегда используйте Формат с этим параметром.

Если в базе номера хранятся с ведущими нулями до фиксированной длины, добавьте их и в параметр: Формат(125, "ЧЦ=4; ЧВН=; ЧГ=0") вернёт "0125". Здесь ЧЦ — общее число знаков, ЧВН — выводить ведущие нули.

Способ 2. Отбор «только цифры» прямо в запросе

Оператор ПОДОБНО понимает диапазоны символов в квадратных скобках. Шаблон [^0-9] означает «любой символ, кроме цифры». Значит, строка без единой нецифры — числовая:

ВЫБРАТЬ
	Номенклатура.Ссылка,
	Номенклатура.Артикул
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.Артикул <> ""
	И НЕ Номенклатура.Артикул ПОДОБНО "%[^0-9]%"

Числа это поле от этого не становится. Зато дальше с результатом можно спокойно работать в коде, не боясь ошибки преобразования.

Способ 3. Перевод в коде и временная таблица

Когда нужен именно числовой диапазон или сумма по номерам, переводите значения в коде, а затем кладите их обратно в запрос временной таблицей. Схема в три шага:

  1. Запросом получить РАЗЛИЧНЫЕ значения текстового поля.
  2. В цикле отобрать числовые и перевести их в число.
  3. Передать таблицу «строка — число» параметром, поместить во временную таблицу и соединить с основной выборкой.
Функция ТолькоЦифры(Знач Стр)
	Стр = СокрЛП(Стр);
	Если Стр = "" Или СтрДлина(Стр) > 15 Тогда
		Возврат Ложь;
	КонецЕсли;
	Для Н = 1 По СтрДлина(Стр) Цикл
		Если СтрНайти("0123456789", Сред(Стр, Н, 1)) = 0 Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	Возврат Истина;
КонецФункции

Соответствие = Новый ТаблицаЗначений;
Соответствие.Колонки.Добавить("Артикул",
	Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(25)));
Соответствие.Колонки.Добавить("АртикулЧислом",
	Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 0)));

Выборка = ЗапросАртикулов.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	Если ТолькоЦифры(Выборка.Артикул) Тогда
		НоваяСтрока = Соответствие.Добавить();
		НоваяСтрока.Артикул = Выборка.Артикул;
		НоваяСтрока.АртикулЧислом = Число(СокрЛП(Выборка.Артикул));
	КонецЕсли;
КонецЦикла;

Дальше основной запрос:

ВЫБРАТЬ
	Т.Артикул,
	Т.АртикулЧислом
ПОМЕСТИТЬ ВТ_Артикулы
ИЗ
	&Соответствие КАК Т
ИНДЕКСИРОВАТЬ ПО
	Т.Артикул
;
ВЫБРАТЬ
	Номенклатура.Ссылка,
	ВТ_Артикулы.АртикулЧислом
ИЗ
	Справочник.Номенклатура КАК Номенклатура
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Артикулы КАК ВТ_Артикулы
		ПО Номенклатура.Артикул = ВТ_Артикулы.Артикул
ГДЕ
	ВТ_Артикулы.АртикулЧислом МЕЖДУ &От И &До
УПОРЯДОЧИТЬ ПО
	ВТ_Артикулы.АртикулЧислом

Типизированные колонки обязательны. Без ОписаниеТипов платформа не сможет поместить таблицу значений во временную таблицу.

В конфигурациях на БСП (Бухгалтерия, ЗУП, УТ) есть готовая функция СтроковыеФункцииКлиентСервер.СтрокаВЧисло. Для нечисловой строки она возвращает Неопределено, а не падает с исключением.

Что вам нужно сделать с текстовым полем?

Сортировка и группировка числовых строк

Строковая сортировка ставит "10" перед "9", потому что символ 1 меньше символа 9. Исправить это можно тремя путями.

Выровнять длину ведущими нулями

Если все значения одной длины — "0009", "0010", "0125", — строковый порядок совпадает с числовым. Тогда и МЕЖДУ "0100" И "0500" даёт правильный диапазон. Это лучший вариант для новых справочников: договоритесь о формате номера с самого начала.

Сортировать по длине, затем по значению

В платформе 8.3.20 и выше в языке запросов появились строковые функции, в том числе ДЛИНАСТРОКИ и СОКРЛП. Для строк из одних цифр без ведущих нулей такой порядок совпадает с числовым:

УПОРЯДОЧИТЬ ПО
	ДЛИНАСТРОКИ(Номенклатура.Артикул),
	Номенклатура.Артикул

Сначала идут все однозначные, затем двузначные и так далее. Для новых функций нужен не только свежий релиз платформы, но и режим совместимости конфигурации не ниже 8.3.20. Прямого приведения строки к числу среди этих функций нет: проверьте синтаксис-помощник своей версии.

Отсортировать уже в коде

Если результат выгружен в таблицу значений с числовой колонкой (способ 3), сортируйте её методом Сортировать("АртикулЧислом"). Для печатной формы на пару сотен строк это проще любых трюков в запросе.

Группировка

Чтобы "0125" и "125" попали в одну группу, их нужно привести к единому виду. Ведущие нули язык запросов отрезать не умеет, поэтому группируйте по числовой колонке из временной таблицы. Хвостовые пробелы на 8.3.20 и выше снимает СОКРЛП(Т.Артикул) прямо в СГРУППИРОВАТЬ ПО.

Грязные данные: пробелы, нули, буквы и пустые значения

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

Что встречается чаще всего:

  • 🔸 Пробелы по краям — следы ручного ввода и загрузки из Excel.
  • 🔸 Строка фиксированной длины. Если у реквизита в конфигураторе задана фиксированная длина, значения дополняются пробелами справа. Шаблон %[^0-9]% тогда отбракует все значения: пробел не цифра.
  • 🔸 Префиксы и разделители: АР-125, 125/1, №125.
  • 🔸 Пустая строка. Под шаблон «нет нецифр» она подходит, поэтому её отсекают отдельным условием.
  • 🔸 Слишком длинное число. Строка из 20 цифр не влезет в Число(15, 0). В функции выше это проверяется по длине.

Проверить базу можно одним запросом-диагностикой:

ВЫБРАТЬ
	Номенклатура.Артикул,
	КОЛИЧЕСТВО(*) КАК Сколько
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.Артикул ПОДОБНО "%[^0-9]%"
СГРУППИРОВАТЬ ПО
	Номенклатура.Артикул

Он покажет все значения, в которых есть хоть один нецифровой символ. Если таких десятки, проще почистить данные, чем усложнять каждый запрос.

Ошибка «Преобразование значения к типу Число не может быть выполнено»

Это исключение кода, а не запроса. Его выбрасывает функция Число(), когда получает строку с буквой или пустую строку. Решение — проверять строку до преобразования, как в функции ТолькоЦифры, или заключить вызов в Попытка … Исключение. Проверка дешевле: исключения в цикле на десятках тысяч строк заметно замедляют обработку.

Массовую правку артикулов или номеров делайте только на копии базы и после согласования. По этим полям могут работать обмены с сайтом, ТСД и поставщиками: изменённое значение перестанет совпадать на другой стороне.

Производительность запросов с текстом как числом

Сравнение строки с числом редко медленное само по себе. Медленными его делают обёртки вокруг поля.

УсловиеИндекс по полюКомментарий
Т.Артикул = &СтрокаиспользуетсяЛучший вариант
Т.Артикул ПОДОБНО "125%"обычно используетсяШаблон начинается с конкретных символов
Т.Артикул ПОДОБНО "%[^0-9]%"нетПросмотр всей таблицы
СОКРЛП(Т.Артикул) = &СтроканетФункция над полем скрывает его от индекса
Соединение с временной таблицей по строкеиспользуетсяЕсли поле проиндексировано

Практические правила:

  1. ✅ Обрабатывайте параметр, а не поле. Формат в коде стоит ноль, функция над полем в ГДЕ стоит просмотра таблицы.
  2. ✅ В ИНДЕКСИРОВАТЬ ПО временной таблицы указывайте поле, по которому идёт соединение.
  3. ✅ Сужайте выборку до перевода в число. Сначала отбор по виду номенклатуры, организации или периоду, потом всё остальное.
  4. ✅ У реквизита, по которому регулярно ищут, должно быть включено свойство «Индексировать» в конфигураторе.

Перевод в коде через временную таблицу быстрый, пока различных значений тысячи или десятки тысяч. На сотнях тысяч он упирается в цикл и передачу данных на сервер. Здесь пора менять метаданные.

Решение в метаданных: отдельный числовой реквизит

Если отчёт по числовому значению нужен постоянно, храните число рядом со строкой. Строковый артикул остаётся для людей и обменов, числовой — для запросов.

Как это устроено

  1. Добавить реквизит, например АртикулЧислом, тип Число(15, 0), свойство «Индексировать» включено.
  2. В модуле объекта, в обработчике ПередЗаписью, заполнять его: если строка числовая — числом, иначе нулём.
  3. Однократной обработкой заполнить реквизит у существующих элементов.
  4. Переписать запросы: отбор и сортировку делать по новому полю.
Процедура ПередЗаписью(Отказ)
	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	Стр = СокрЛП(Артикул);
	АртикулЧислом = ?(ТолькоЦифры(Стр), Число(Стр), 0);
КонецПроцедуры

Учтите проверку ОбменДанными.Загрузка: при загрузке через обмен обработчик выходит сразу, и реквизит не заполнится. Если данные приходят из обменов, заполняйте поле и там, либо уберите эту проверку осознанно.

Типовая конфигурация: только через расширение

В Бухгалтерии, ЗУП или УТ не снимайте конфигурацию с поддержки ради одного реквизита. Добавьте его в расширении: начиная с платформы 8.3.11 к заимствованным объектам можно добавлять собственные реквизиты. Код заполнения пишется в модуле объекта расширения через &После("ПередЗаписью").

Сменить тип поля целиком

Если в поле никогда не было букв, реквизит можно перевести на тип «Число». При обновлении структуры базы платформа попытается сконвертировать существующие значения. Перед этим обязательно:

  • 🔹 выполнить запрос-диагностику из раздела о грязных данных;
  • 🔹 сделать выгрузку .dt и проверить результат на копии;
  • 🔹 найти все места, где поле используется как строка: обмены, печатные формы, поиск в формах.

Обновление структуры требует монопольного доступа к базе. Все пользователи будут отключены, поэтому делайте это вне рабочего времени.

Частые вопросы

Можно ли в запросе 1С превратить число в строку?
Нет, ВЫРАЗИТЬ этого не умеет. Переведите число в строку в коде через Формат с ЧГ=0 и передайте параметром.
Почему ПОДОБНО "%[^0-9]%" не отбирает ни одного значения?
Скорее всего, у реквизита задана фиксированная длина и значения дополнены пробелами. Пробел не цифра, поэтому под шаблон попадает каждая строка.
Работает ли такой отбор в отчёте на СКД?
Да. Условие с ПОДОБНО пишется в тексте запроса набора данных. Числовую колонку можно подать в отчёт отдельным внешним набором данных — таблицей значений, подготовленной в коде.
Как найти договор, если номер в базе записан с префиксом, например ДГ-125?
Используйте ПОДОБНО “%125” или ПОДОБНО “ДГ-125”. Если нужен именно числовой хвост для диапазона, вырежьте его в коде и положите во временную таблицу.
Что быстрее: Попытка с Число() или проверка цифр?
Проверка цифр. Исключения в цикле обходятся дороже, особенно на десятках тысяч строк.