Как работает «=» в коде, запросах и настройках отчётов 1С
Содержание
Во встроенном языке 1С знак равно делает две разные вещи: в начале оператора он присваивает значение (Сумма = 100;), а внутри выражения сравнивает (Если Сумма = 100 Тогда). Отдельного оператора ==, как в C или JavaScript, нет. В языке запросов и в отборах отчётов «=» означает только сравнение.
Путаница начинается на стыке: строка не равна сама себе из-за пробела, ссылка никогда не равна названию контрагента, а условие Поле = NULL в запросе не находит ни одной записи. Все эти случаи объясняются тем, что «=» сравнивает значение вместе с его типом.
Присваивание: «=» в начале оператора
Если строка кода начинается с переменной, реквизита или элемента коллекции, за которым идёт «=», платформа читает это как присваивание. Всё, что справа, вычисляется и записывается в то, что слева.
Сумма = 1500;
Объект.Комментарий = "Создан обработкой";
Структура.Вставить("Ставка", 20);
Структура.Ставка = 22;
ТаблицаТоваров[0].Количество = 3;
Что важно знать про присваивание:
- 📌 Переменную объявлять не обязательно. Первое присваивание создаёт локальную переменную.
Перемнужен для переменных модуля и для читаемости. - 🔁 Цепочки не работают как в C.
А = Б = 5;не запишет пятёрку в обе переменные. Первый знак — присваивание, второй — сравнение: вАпопадётИстинаилиЛожьв зависимости от того, равно лиБпяти. - 📦 Объекты присваиваются по ссылке. После
Массив2 = Массив1;обе переменные указывают на один и тот же массив. Добавили элемент вМассив2— он появился и вМассив1.
Нужна независимая копия коллекции — создайте новую и перенесите элементы. В конфигурациях на БСП для этого есть ОбщегоНазначения.СкопироватьРекурсивно(Значение), она копирует вложенные структуры и массивы.
Для таблиц значений есть метод Скопировать(): НоваяТаблица = Таблица.Скопировать();. Он создаёт отдельную таблицу, а не вторую ссылку на старую.
Сравнение в условиях: «=» внутри выражения
Везде, где ожидается логическое значение, «=» сравнивает два операнда и возвращает Истина или Ложь. Это условия Если, ИначеЕсли, Пока, тернарный оператор ?(), правая часть присваивания.
Если Документ.Проведен = Истина Тогда
// ...
КонецЕсли;
Пока Остаток = 0 Цикл
// ...
КонецЦикла;
Текст = ?(Количество = 1, "товар", "товаров");
ЭтоРубли = (Валюта = Константы.ВалютаРегламентированногоУчета.Получить());
Последняя строка показывает оба смысла сразу: первое «=» присваивает, второе в скобках сравнивает. Скобки здесь не обязательны, но с ними код читается без усилий.
Полный набор операций сравнения:
| Операция | Значение | Пример |
|---|---|---|
= | равно | Код = "000001" |
<> | не равно | Статус <> Перечисления.СтатусыЗаказов.Закрыт |
<, > | меньше, больше | Сумма > 0 |
<=, >= | меньше или равно, больше или равно | Дата >= НачалоМесяца(ТекущаяДата()) |
Знака != в языке нет, только <>. Отрицание через НЕ тоже возможно, но Если НЕ (А = Б) проще записать как Если А <> Б.
Чтобы не гадать о приоритете НЕ и операций сравнения, всегда берите сравнение в скобки: НЕ (Сумма = 0). Без скобок такие условия легко прочитать неправильно при ревью.
Про булевы реквизиты. Если Флаг = Истина Тогда и Если Флаг Тогда дают одно и то же, когда в Флаг лежит булево. Разница появляется, если значение может быть Неопределено: короткая запись упадёт с ошибкой преобразования к булеву, а сравнение с Истина просто вернёт Ложь.
Как «=» сравнивает разные типы данных
Именно здесь чаще всего рождаются ошибки. Правило одно: «=» сравнивает значения с учётом типа. Если типы разные, результат — Ложь, без исключения.
Сообщить(1 = "1"); // Ложь: число и строка
Сообщить("1" = Строка(1)); // Истина
Сообщить(Число("1") = 1); // Истина
С операциями < и > так не выйдет: для значений разных типов платформа выдаёт ошибку выполнения. Равенство же молча возвращает Ложь, и ошибка в логике может жить годами.
Строки
- 🔠 Регистр учитывается.
"Ромашка" = "ромашка"даётЛожь. - 📏 Пробелы учитываются.
"ООО Ромашка" = "ООО Ромашка "даётЛожь. Хвостовые пробелы часто приходят из загрузки Excel или из реквизитов фиксированной длины.
Как сравнить «по-человечески»:
// Без учёта регистра
Если ВРег(СокрЛП(Стр1)) = ВРег(СокрЛП(Стр2)) Тогда
// ...
КонецЕсли;
// Функция СтрСравнить не учитывает регистр, 0 означает равенство
Если СтрСравнить(СокрЛП(Стр1), СокрЛП(Стр2)) = 0 Тогда
// ...
КонецЕсли;
Числа
Тип «Число» в 1С десятичный, поэтому классической проблемы двоичной дроби нет: 0.1 + 0.2 = 0.3 возвращает Истина. Но результат деления хранится с ограниченной точностью, а реквизиты обрезаются по своей разрядности при записи.
Поэтому вычисленную сумму перед сравнением с суммой из базы округляйте до той же точности:
Если Окр(Цена * Количество, 2) = СтрокаТЧ.Сумма Тогда
// суммы совпадают с точностью до копейки
КонецЕсли;
Даты
Дата в 1С всегда содержит время. '20261007' = '20261007153000' даёт Ложь: у второго значения есть 15:30:00. Сравнить «один и тот же день» можно так:
Если НачалоДня(Документ.Дата) = НачалоДня(ТекущаяДатаСеанса()) Тогда
// документ сегодняшний
КонецЕсли;
Ссылки, объекты и коллекции
| Что сравниваем | Когда «=» вернёт Истина |
|---|---|
Ссылки (СправочникСсылка, ДокументСсылка) | Обе указывают на один и тот же элемент базы |
| Ссылка и строка с наименованием | Никогда — разные типы |
| Пустая ссылка | Ссылка = Справочники.Контрагенты.ПустаяСсылка() или Ссылка.Пустая() |
| Значения перечисления | Вид = Перечисления.ВидыКонтрагентов.ЮрЛицо |
| Объекты, массивы, структуры | Только если это один и тот же экземпляр в памяти |
| Тип значения | ТипЗнч(Значение) = Тип("Строка") |
Два массива с одинаковыми элементами не равны друг другу. Две структуры с одинаковыми ключами и значениями — тоже. Сравнивать их приходится поэлементно.
Неопределено и Null
Во встроенном языке Неопределено = Неопределено и Null = Null дают Истина, а Неопределено = Null — Ложь. Это частая ловушка при разборе результата запроса: незаполненное поле из левого соединения приходит как Null, а не как Неопределено и не как пустая строка.
Если Выборка.Цена = Null Тогда
Цена = 0;
КонецЕсли;
Короче то же самое делает функция ЗначениеЗаполнено(): она вернёт Ложь для Null, Неопределено, пустой строки, нуля, пустой даты и пустой ссылки.
Знак равно в языке запросов 1С
В тексте запроса «=» никогда не присваивает. Он работает в условиях ГДЕ, ИМЕЮЩИЕ, в связях соединений ПО и в выражениях ВЫБОР КОГДА.
ВЫБРАТЬ
Продажи.Номенклатура,
ВЫБОР
КОГДА Продажи.Количество = 0 ТОГДА "Без количества"
ИНАЧЕ "Обычная строка"
КОНЕЦ КАК Признак
ИЗ
РегистрНакопления.Продажи КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
ПО Продажи.Номенклатура = Номенклатура.Ссылка
ГДЕ
Продажи.Контрагент = &Контрагент
И Продажи.Период >= &НачалоПериода
Отличия от встроенного языка, которые нужно держать в голове:
- NULL сравнивают только через
ЕСТЬ NULL. УсловиеПоле = NULLне вернёт ни одной строки, даже там, где значение действительно пустое. Правильно:ГДЕ Цены.Цена ЕСТЬ NULLилиГДЕ НЕ Цены.Цена ЕСТЬ NULL. - Предопределённые значения и пустые ссылки — через
ЗНАЧЕНИЕ(). Пример:ГДЕ Заказы.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказов.Закрыт)илиПоле = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка). - Для списка значений нужен
В, а не «=». Если в параметр передан массив или список значений, пишитеГДЕ Товары.Номенклатура В (&СписокТоваров). - Строки неограниченной длины напрямую не сравнить. Реквизит-строка без ограничения длины (типично «Комментарий») в условии с «=» даёт ошибку запроса. Обрежьте его:
ПОДСТРОКА(Документ.Комментарий, 1, 200) = &Текст. - Составной тип проверяют через
ССЫЛКА.ГДЕ Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуготбирает строки нужного типа, а «=» проверяет уже конкретное значение.
Регистр букв при сравнении строк в запросе обычно не учитывается, а хвостовые пробелы отбрасываются. Это поведение зависит от СУБД и её настроек, поэтому не опирайтесь на него в критичной логике — проверьте на своей базе.
Значения в запрос передавайте параметрами (&Контрагент), а не склейкой строки. Так не будет проблем с типами, кавычками и форматом даты.
Вид сравнения «Равно» в отборах списков и отчётов
В пользовательском режиме знак равно превращается в вид сравнения «Равно». Он есть в настройках отбора динамических списков, в отчётах на системе компоновки данных (СКД) и в отборах регистров.
Как задать отбор «Равно» руками:
- В списке откройте меню Ещё и выберите настройку списка, вкладку Отбор. В отчёте нажмите кнопку Настройки и перейдите к отборам.
- Добавьте поле, например «Контрагент».
- В колонке вида сравнения выберите Равно.
- Укажите значение и включите флажок использования.
Чем «Равно» отличается от соседних видов сравнения:
| Вид сравнения | Что отберёт | Когда выбирать |
|---|---|---|
| Равно | Ровно одно значение | Конкретный контрагент, склад, организация |
| Не равно | Всё, кроме значения | Исключить одну организацию |
| В списке | Любое из нескольких значений | Три склада из десяти |
| В группе | Элемент и всех подчинённых | Группа номенклатуры со всеми вложенными |
| Содержит | Подстроку в строке | Поиск по части наименования |
Для иерархических справочников «Равно» по группе не захватывает её элементы. Отбор «Номенклатура Равно Молочная продукция» покажет только строки, где выбрана сама группа, то есть обычно ничего. Нужен вид «В группе».
Отбор «Равно» из кода
Динамический список:
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Контрагент;
ЭлементОтбора.Использование = Истина;
Набор записей регистра: метод Установить() у элемента отбора сам ставит сравнение на равенство.
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(Номенклатура);
НаборЗаписей.Прочитать();
Поиск в таблице значений по равенству полей:
Отбор = Новый Структура("Склад, Номенклатура", Склад, Номенклатура);
НайденныеСтроки = ТаблицаОстатков.НайтиСтроки(Отбор);
НайтиСтроки сравнивает поля по тем же правилам, что и «=»: с учётом типа, регистра и пробелов.
В вычисляемых полях и выражениях СКД синтаксис ближе к языку запросов: ВЫБОР КОГДА Сумма = 0 ТОГДА "—" ИНАЧЕ Сумма КОНЕЦ.
Проверьте себя
Ошибки с оператором равно и как их найти
Ещё одна тихая ошибка — сравнение суммы документа с вычисленным значением без округления. Расхождение в долях копейки даёт Ложь, и проверка срабатывает там, где визуально всё сходится. Округляйте вычисление до разрядности реквизита, как в примере выше.
Чтобы быстро понять, что именно лежит в переменной, остановитесь в отладчике на строке сравнения и посмотрите значение и его тип в табло. Тип часто объясняет всё сразу: вместо ожидаемой ссылки там строка, вместо даты — Неопределено.