К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как сравнить два поля в 1С

Как сравнить два поля в 1С: операторы сравнения в запросе и коде, сравнение строк, дат, ссылок, типов. Примеры кода, частые ошибки и проверка результата.

Сравнение двух полей — одна из самых частых задач в 1С: нужно проверить, совпадает ли контрагент в документе и в регистре, отличается ли цена продажи от цены закупки, совпадает ли дата отгрузки с датой заказа. В зависимости от того, где выполняется сравнение — в коде на встроенном языке, в запросе, в отборе динамического списка или в СКД — применяются разные инструменты.

Главная сложность в том, что 1С строго типизирована: поле сравнивается с учётом типа значения, и сравнение строки с числом или ссылки с неопределённым значением может дать неожиданный результат. Поэтому перед сравнением важно понимать, какие типы хранят поля, и при необходимости приводить их к общему виду.

Ниже разобраны основные способы сравнения: операторы встроенного языка, конструкции запроса, сравнение строк с учётом регистра, работа с датами, ссылками и составными типами, а также типичные ошибки, которые приводят к ложным результатам.

Сравнение полей в коде на встроенном языке

В модуле объекта, формы или общем модуле поля сравнивают стандартными операторами: =, <>, >, <, >=, <=. Результат — значение типа Булево, которое обычно используется в условии Если ... Тогда.

Если Объект.СуммаДокумента > Объект.СуммаОплаты Тогда

Сообщить("Документ оплачен не полностью");

КонецЕсли;

Операторы упорядочивания (>, <) корректно работают для чисел, дат и строк. Для ссылочных типов осмысленны только проверки равенства и неравенства: две ссылки равны, если указывают на один и тот же объект базы данных. Сравнивать ссылки по представлению (наименованию) — ошибка: у разных элементов могут совпадать наименования, а у одного элемента наименование может меняться.

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

Сравнение двух полей в запросе

В тексте запроса поля сравниваются прямо в условии ГДЕ или в соединении таблиц. Это типовой способ найти расхождения между двумя источниками данных — например, документы, где сумма по табличной части не совпадает с итоговой суммой шапки.

ВЫБРАТЬ

Реализация.Ссылка,

Реализация.СуммаДокумента,

ЕСТЬNULL(Оплаты.СуммаОплаты, 0) КАК СуммаОплаты

ИЗ

Документ.РеализацияТоваровУслуг КАК Реализация

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Оплаты КАК Оплаты

ПО Реализация.Ссылка = Оплаты.ДокументОснование

ГДЕ

Реализация.СуммаДокумента <> ЕСТЬNULL(Оплаты.СуммаОплаты, 0)

Ключевой момент — значения NULL. При левом соединении, если записи во второй таблице нет, поле будет NULL, и любое сравнение с NULL даст не Истина и не Ложь, а «неопределённость»: такая строка просто не пройдёт условие. Поэтому поля из присоединяемых таблиц всегда оборачивайте в ЕСТЬNULL().

Для сравнения полей составного типа (например, поле «Документ» может хранить разные виды документов) сравнение по равенству в запросе работает корректно: ссылки разных типов не равны между собой. Но если нужно сравнить только по типу, используйте ТИПЗНАЧЕНИЯ() или оператор ССЫЛКА.

bsl
ЕСЛИ ТипЗнч(Поле1) = ТипЗнч(Поле2) И Поле1 = Поле2 ТОГДА
    // значения совпадают и по типу, и по значению
КОНЕЦЕСЛИ;

Сравнение строк: регистр, пробелы и длина

Строки в 1С сравниваются с учётом регистра: «Петров» и «ПЕТРОВ» — разные значения для оператора равенства. Если нужно сравнение без учёта регистра, приведите обе строки к одному регистру функциями ВРег() или НРег().

Если ВРег(СокрЛП(Поле1)) = ВРег(СокрЛП(Поле2)) Тогда

// строки совпадают без учёта регистра и краевых пробелов

КонецЕсли;

Частая причина «ложного» несовпадения — неразрывные пробелы и невидимые символы, попавшие в данные при копировании из Excel или веб-страниц. Функция СокрЛП() удаляет обычные пробелы по краям, но не внутри строки и не все нестандартные символы. Для надёжного сравнения наименований из внешних источников данные лучше предварительно нормализовать.

В запросе для строк доступен оператор ПОДОБНО с шаблоном, но он сравнивает поле с литералом, а не с другим полем. Для сравнения двух строковых полей в запросе используйте обычное равенство, помня про регистр и фиксированную длину строк: строки фиксированной длины дополняются пробелами, и это влияет на сравнение.

Типичные ошибки
01
Сравнение строк без СокрЛП() — скрытые пробелы дают ложное несовпадение
02
Сравнение ссылок по наименованию вместо сравнения самих ссылок
03
Игнорирование NULL при соединении таблиц в запросе — расхождения теряются
04
Сравнение даты с пустой датой без проверки — пустая дата меньше любой заполненной
05
Сравнение чисел с разной точностью после деления — копейки дают ложное неравенство

Сравнение дат, чисел и ссылок

Даты сравниваются операторами упорядочивания, при этом учитывается время: две даты одного дня, но с разным временем, не равны. Если нужно сравнить только день, отсеките время функцией НачалоДня() в коде или НАЧАЛОПЕРИОДА(Поле, ДЕНЬ) в запросе.

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

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

Ссылки сравниваются быстро и надёжно: Ссылка1 = Ссылка2 — это сравнение уникальных идентификаторов без обращения к данным объекта. Пустые ссылки разных типов не равны между собой, поэтому для проверки «поле не заполнено» используйте ЗначениеЗаполнено() или сравнение с ПустаяСсылка() конкретного типа.

Контрольные точки

Как проверить результат

Совпадение строк
Норма

Строки совпадают после СокрЛП и приведения регистра

Тревожный признак

Равные на вид строки не равны — ищите скрытые символы

Сравнение в запросе с соединением
Норма

ЕСТЬNULL применён ко всем полям присоединяемой таблицы

Тревожный признак

Записи без пары во второй таблице пропадают из результата

Сравнение дат
Норма

Время отсечено, если сравниваются только дни

Тревожный признак

Даты одного дня признаются разными из-за времени

Сравнение полей в отборах, СКД и динамических списках

В настройках динамического списка и отчёта на СКД сравнение двух полей задаётся через пользовательское поле-выражение или отбор с видом сравнения. В простом отборе динамического списка правое значение — обычно константа, поэтому для сравнения двух полей таблицы нужно добавить условие в текст запроса списка.

В СКД удобно создать вычисляемое поле с выражением вида Выбор Когда Поле1 = Поле2 Тогда "Совпадает" Иначе "Расходится" Конец и дальше фильтровать или раскрашивать строки по нему через условное оформление. Так пользователь получает наглядный признак расхождения без доработки конфигурации.

Для сравнения данных двух таблиц целиком (например, двух версий загруженного прайса) удобна консольная обработка с пакетным запросом: полное соединение по ключевому полю и условие, где одна из ссылок есть NULL, покажет строки, присутствующие только в одной из таблиц.

Порядок действий при сравнении двух полей
  1. 1
    Определите типы обоих полей: число, строка, дата, ссылка, составной тип
  2. 2
    Выберите место сравнения: код, запрос, отбор или СКД
  3. 3
    Обработайте пустые значения: ЗначениеЗаполнено() в коде, ЕСТЬNULL() в запросе
  4. 4
    Нормализуйте строки: СокрЛП(), ВРег(), при необходимости удаление лишних символов
  5. 5
    Для дат решите, важно ли время; для сумм — округлите до нужной точности
  6. 6
    Проверьте результат на тестовых данных с заведомо известными совпадениями и расхождениями

Составные типы и сравнение по типу значения

Если поле имеет составной тип, одного сравнения значений мало: одинаковое строковое представление может скрывать разные типы. Функция ТипЗнч() возвращает тип значения, и её результат можно сравнивать с типом другого поля или с типом из метаданных.

Если ТипЗнч(Документ1) = Тип("ДокументСсылка.РеализацияТоваровУслуг")

И Документ1 = Документ2 Тогда

// оба поля — ссылки на один и тот же документ реализации

КонецЕсли;

В запросе аналогом служит функция ТИПЗНАЧЕНИЯ(Поле) и проверка Поле ССЫЛКА Справочник.Номенклатура. Это особенно полезно при сравнении полей в регистрах с составными измерениями, где один и тот же реквизит заполняется объектами разных видов.

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

Частые ошибки и ограничения

Самая распространённая ошибка — сравнение значений разных типов без явного приведения. Встроенный язык в ряде случаев выполняет неявное преобразование, но правила преобразования нетривиальны, и результат может отличаться от ожидаемого. Явное приведение через Строка(), Число(), Дата() делает код предсказуемым.

Вторая группа ошибок связана с NULL в запросах и с пустыми значениями в коде. Любое сравнение с NULL в запросе не даёт Истину, поэтому строки с расхождениями могут молча выпадать из выборки. В коде пустая ссылка, пустая дата и пустая строка — разные значения, и универсальная проверка на «пустоту» выполняется только через ЗначениеЗаполнено().

Третья группа — производительность: сравнение полей с функциями над ними в условии запроса (например, ВРЕГ(Поле) = ВРЕГ(ДругоеПоле)) не использует индексы и приводит к полному сканированию таблицы. На больших таблицах лучше хранить нормализованное значение в отдельном реквизите и сравнивать его.

Итог

Что важно запомнить

Сравнивайте поля с учётом типа: операторы в коде, условие ГДЕ в запросе. Обрабатывайте NULL через ЕСТЬNULL, пустые значения — через ЗначениеЗаполнено, строки нормализуйте, даты приводите к нужной точности. Проверяйте логику на тестовых данных с известным результатом.

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

Как сравнить два поля, если одно из них может быть NULL в запросе?

Оберните поле в функцию ЕСТЬNULL(Поле, ЗначениеПоУмолчанию) с обеих сторон сравнения или только со стороны присоединяемой таблицы. Без этого строки с NULL не пройдут условие, и расхождения будут потеряны.

Почему строки выглядят одинаково, но сравнение даёт «ложь»?

Чаще всего виноваты пробелы по краям, неразрывные пробелы или разный регистр букв. Примените СокрЛП() к обеим строкам и приведите их к одному регистру через ВРег(). Если не помогло, проверьте коды символов — в данных могут быть невидимые символы из внешних источников.

Можно ли сравнить два поля в отборе динамического списка без изменения запроса?

Стандартный отбор сравнивает поле только с константой или параметром. Для сравнения двух полей таблицы нужно изменить текст запроса списка (добавить условие ГДЕ) либо использовать произвольный запрос с флагом «Произвольный запрос» в настройках списка.

Как сравнить даты без учёта времени?

В коде используйте НачалоДня(Дата1) = НачалоДня(Дата2). В запросе — НАЧАЛОПЕРИОДА(Поле, ДЕНЬ) для обоих полей. Без этого две даты одного дня с разным временем будут признаны разными.

Как сравнить ссылки двух разных типов документов?

Прямое равенство вернёт «ложь», так как ссылки разных типов никогда не равны. Если нужно проверить совпадение по смыслу, сравнивайте реквизиты ссылок (например, номер и дату) или сначала проверяйте тип через ТипЗнч() и ТИПЗНАЧЕНИЯ() в запросе.

Что быстрее: сравнение в запросе или перебор в коде?

Для больших объёмов данных сравнение в запросе почти всегда быстрее: сервер СУБД выполняет соединение и фильтрацию без передачи всех записей на клиент. Перебор в цикле оправдан только для небольших выборок или когда сравнение требует сложной логики, невыразимой в запросе.