Условия в 1С: оператор Если, тернарник и ВЫБОР в запросе

· 9 мин

Содержание

Условие в 1С задаётся двумя разными инструментами, и выбор зависит от того, где вы пишете код. Во встроенном языке ветвление делает оператор Если … Тогда … КонецЕсли, а в тексте запроса — секция ГДЕ для отбора строк и выражение ВЫБОР КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ для вычисляемых полей.

Логику внутри условия собирают из сравнений (=, <>, >, <, >=, <=) и логических операторов И, ИЛИ, НЕ. Для короткой проверки «одно значение или другое» есть тернарный оператор ?(). Ниже — синтаксис каждого способа с рабочими примерами и таблица, когда какой применять.

Всё описанное относится к платформе 1С:Предприятие 8.3 и встроенному языку — он одинаков в Бухгалтерии, ЗУП, Управлении торговлей и любой другой конфигурации.

Оператор Если: основное ветвление во встроенном языке

Базовая конструкция состоит из ключевого слова Если, самого условия, слова Тогда и блока команд. Завершается всё обязательным КонецЕсли с точкой с запятой.

Если Сумма > 1000 Тогда
    Скидка = 10;
КонецЕсли;

Если нужно обработать противоположный случай, добавляют ветку Иначе. Она срабатывает, когда условие ложно.

Если Контрагент.ЮрЛицо Тогда
    СтавкаНДС = СтавкаНДС20;
Иначе
    СтавкаНДС = БезНДС;
КонецЕсли;

Для нескольких взаимоисключающих вариантов используют цепочку ИначеЕсли. Платформа проверяет условия сверху вниз и выполняет первый подошедший блок, остальные пропускает.

Если Количество > 100 Тогда
    Категория = "Крупный опт";
ИначеЕсли Количество > 10 Тогда
    Категория = "Мелкий опт";
ИначеЕсли Количество > 0 Тогда
    Категория = "Розница";
Иначе
    Категория = "Нет остатка";
КонецЕсли;

Отдельного оператора Выбор/switch, как в некоторых языках, во встроенном языке 1С нет. Многовариантный выбор делают именно цепочкой ИначеЕсли. Слово ВЫБОР существует только в языке запросов — о нём ниже.

Условие может ссылаться на реквизиты объекта, переменные, результат функции — на любое выражение, которое возвращает Истина или Ложь. Булев реквизит (флажок) подставляют прямо, без сравнения с Истина:

Если Документ.Проведён Тогда   // так правильно
Если Документ.Проведён = Истина Тогда   // так избыточно, хотя тоже работает

Логические операторы И, ИЛИ, НЕ

Когда в условии несколько проверок, их соединяют логическими операторами. В 1С их три:

  • ✅ И — истинно, когда истинны оба операнда (логическое умножение).
  • ✅ ИЛИ — истинно, когда истинен хотя бы один операнд.
  • ✅ НЕ — инвертирует значение: НЕ Истина даёт Ложь.
Если (Статус = "Оплачен") И НЕ Заказ.Отменён Тогда
    Отгрузить = Истина;
КонецЕсли;

Приоритет такой: сначала НЕ, затем И, затем ИЛИ. Из-за этого выражение без скобок читается не всегда так, как задумано. Сравните:

// A ИЛИ B И C  платформа понимает как  A ИЛИ (B И C)
Если Срочно ИЛИ Сумма > 1000 И Предоплата Тогда

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

Если Срочно ИЛИ (Сумма > 1000 И Предоплата) Тогда

Ещё одна особенность — «ленивое» вычисление. В связке через И платформа не проверяет второй операнд, если первый уже Ложь. Это удобно для защиты от обращения к пустой ссылке:

Если ЗначениеЗаполнено(Контрагент) И Контрагент.ЮрЛицо Тогда

Здесь Контрагент.ЮрЛицо вычислится только после того, как первая проверка подтвердит, что ссылка заполнена. Поменяете части местами — получите ошибку на пустом значении.

Тернарный оператор ?() — условие в одну строку

Когда нужно не выполнить команды, а просто выбрать одно из двух значений, разворачивать Если … КонецЕсли на пять строк необязательно. Для этого есть тернарный оператор:

?(Условие, ЗначениеЕслиИстина, ЗначениеЕслиЛожь)

Он возвращает второй аргумент, если условие истинно, и третий — если ложно.

Скидка = ?(Сумма > 1000, 10, 0);
Обращение = ?(Пол = Перечисления.Пол.Мужской, "Уважаемый", "Уважаемая");

Тернарник удобен прямо внутри других выражений — например, при сборке строки сообщения или при заполнении реквизита:

Сообщить("Заказ " + Номер + ?(Срочно, " (СРОЧНО)", ""));

Не вкладывайте тернарники друг в друга на три-четыре уровня: ?(A, 1, ?(B, 2, ?(C, 3, 4))) читается тяжело. Для трёх и более вариантов возьмите обычную цепочку ИначеЕсли — её проще сопровождать.

Условие отбора в запросе: секция ГДЕ

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

ВЫБРАТЬ
    Номенклатура.Наименование,
    Номенклатура.Артикул
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    НЕ Номенклатура.ПометкаУдаления
    И Номенклатура.Родитель = &ГруппаТовары

Значения, которые приходят извне (из формы, из кода), подставляют через параметры — имя с амперсандом: &ГруппаТовары, &ДатаНачала. Их значения задаются методом УстановитьПараметр у объекта запроса.

Для диапазонов и списков есть специальные конструкции:

ГДЕ
    Продажи.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
    И Продажи.Склад В (&СписокСкладов)
    И Продажи.Контрагент ССЫЛКА Справочник.Контрагенты

Для условия по части строки берут оператор ПОДОБНО с шаблоном, где % заменяет любое число символов, а _ — один:

ГДЕ
    Номенклатура.Наименование ПОДОБНО "%кабель%"

Так отберутся все позиции, в названии которых встречается «кабель». Проверку на пустую ссылку в условии отбора делают сравнением с пустым значением соответствующего типа: ГДЕ Документ.Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка).

Конструктор запроса вместо ручного набора

Текст запроса редко пишут руками с нуля. В Конфигураторе и в режиме «Предприятие» (консоль запросов, обработки разработчика) есть конструктор запроса — визуальный редактор. Его вызывают из контекстного меню строки с текстом запроса командой Конструктор запроса.

Условия задаются на вкладке Условия: перетаскиваете поле, выбираете операцию сравнения, указываете значение или параметр. Конструктор сам соберёт корректную секцию ГДЕ и расставит скобки. Это удобно, пока условий немного; сложную логику с вложенными ИЛИ всё равно проще дописать руками в тексте.

Выражение ВЫБОР КОГДА: условие прямо в поле запроса

Секция ГДЕ отбирает строки целиком. А если нужно в самом поле вычислить значение по условию — например, вывести текстовую метку вместо числа, — применяют конструкцию ВЫБОР. Это аналог Если внутри запроса.

ВЫБРАТЬ
    Товары.Номенклатура,
    ВЫБОР
        КОГДА Товары.Количество > 100 ТОГДА "Много"
        КОГДА Товары.Количество > 10  ТОГДА "Средне"
        КОГДА Товары.Количество > 0   ТОГДА "Мало"
        ИНАЧЕ "Нет в наличии"
    КОНЕЦ КАК Доступность
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Товары

Правила те же, что у ИначеЕсли: условия КОГДА проверяются по очереди, срабатывает первое истинное. Ветка ИНАЧЕ необязательна — если её нет и ни одно КОГДА не подошло, поле получит NULL.

Выражение ВЫБОР можно использовать не только для вывода, но и в группировке, упорядочивании, в условиях соединений. Частый приём — считать количество строк, удовлетворяющих условию, через сумму единиц и нулей:

СУММА(ВЫБОР КОГДА Продажи.Сумма > 0 ТОГДА 1 ИНАЧЕ 0 КОНЕЦ) КАК КоличествоПродаж
Проверьте себя
Чем `ВЫБОР КОГДА` в запросе отличается от секции `ГДЕ`?
- `ВЫБОР` быстрее работает
Какой оператор вернёт значение одного из двух прямо в строке кода?
- `Если … КонецЕсли`
В каком порядке платформа вычисляет логическое выражение без скобок?
- Слева направо

Условное оформление: условие без кода

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

В настройках списка или отчёта (компоновка данных) открываете вкладку Условное оформление и добавляете элемент. В нём три блока:

  1. Оформление — что меняем: цвет текста, фон, шрифт, формат.
  2. Условие — при каком значении поля оформление применится (то же сравнение полей, что в отборе).
  3. Оформляемые поля — к каким колонкам применить.

Пример: выделить красным фоном строки, где Остаток < 0. Задаёте поле Остаток, вид сравнения Меньше, значение 0 — и платформа подсветит нужные строки сама, без обработчиков.

Условное оформление считается на стороне компоновки и не тормозит форму. Если то же самое делать кодом в обработчике ПриВыводеСтроки, на больших списках это заметно медленнее.

Проверка значений: Неопределено, NULL и защита от ошибок

Условие часто падает не из-за логики, а из-за того, что сравниваемое значение «пустое». В 1С пустота бывает разной, и путать её нельзя:

  • Неопределено — значение не задано (пустая переменная, несуществующий реквизит).
  • NULL — приходит из запроса, когда в соединении нет данных или нет ветки ИНАЧЕ.
  • Пустая ссылка, пустая строка, 0, Ложь — это заполненные, но «нулевые» значения.

Проверять заполненность во встроенном языке удобнее всего функцией ЗначениеЗаполнено() — она возвращает Ложь сразу для Неопределено, NULL, пустой ссылки, пустой строки и нулевой даты:

Если ЗначениеЗаполнено(Контрагент) Тогда
    // ссылка точно не пустая
КонецЕсли;

В запросах NULL нельзя сравнивать через =. Для него есть отдельная функция ЕСТЬNULL(Поле, ЗначениеПоУмолчанию), которая подменяет пустоту на нужное значение:

ВЫБРАТЬ
    ЕСТЬNULL(Остатки.Количество, 0) КАК Количество

Отдельная история — ошибки времени выполнения: деление на ноль, конвертация строки в число, обращение к недоступному сервису. Их перехватывают конструкцией Попытка … Исключение … КонецПопытки. Код в блоке Попытка выполняется, и если возникает ошибка, управление уходит в Исключение, а программа не падает.

Попытка
    Коэффициент = Выручка / Количество;
Исключение
    Коэффициент = 0;
    ЗаписьЖурналаРегистрации("Расчёт", УровеньЖурналаРегистрации.Ошибка,
        , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;

Не превращайте Попытка в «глушилку» ошибок с пустым блоком Исключение — так вы прячете реальные сбои. Перехватывайте только то, что действительно может возникнуть, и обязательно пишите причину в журнал регистрации через ИнформацияОбОшибке().

Какой способ условия выбрать

Инструментов несколько, и каждый — под свою задачу. Короткая шпаргалка:

ЗадачаИнструментГде пишется
Выполнить разные командыЕсли … ИначеЕсли … КонецЕслиВстроенный язык
Выбрать одно из двух значенийТернарный ?()Встроенный язык
Оставить нужные строки выборкиСекция ГДЕЗапрос
Вычислить значение поля по условиюВЫБОР КОГДА … КОНЕЦЗапрос
Подменить NULL в запросеЕСТЬNULL()Запрос
Покрасить строки/ячейки по условиюУсловное оформлениеНастройка списка/отчёта
Защититься от ошибки выполненияПопытка … ИсключениеВстроенный язык

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

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

Можно ли во встроенном языке 1С написать switch или case?
Отдельного оператора выбора по значению нет. Многовариантную проверку делают цепочкой ИначеЕсли. Слово ВЫБОР есть только в языке запросов — это выражение ВЫБОР КОГДА … ТОГДА … ИНАЧЕ … КОНЕЦ, которое возвращает значение, а не выполняет команды.
Почему условие с ИЛИ и И работает не так, как я ожидал?
Из-за приоритета операторов: сначала вычисляется НЕ, затем И, и только потом ИЛИ. Выражение A ИЛИ B И C платформа читает как A ИЛИ (B И C). Ставьте скобки вокруг каждой логической группы — результат станет однозначным.
Как в условии проверить, что реквизит не заполнен?
Во встроенном языке — функцией ЗначениеЗаполнено(): она сразу отсекает Неопределено, NULL, пустую ссылку, пустую строку и нулевую дату. В запросе пустое значение после соединения приходит как NULL, и сравнивать его через = нельзя — используйте ЕСТЬNULL(Поле, 0).
В чём разница между секцией ГДЕ и выражением ВЫБОР в запросе?
ГДЕ фильтрует: отбирает строки, которые попадут в результат. ВЫБОР КОГДА вычисляет: формирует значение в конкретном поле, оставляя все строки на месте. Их часто используют вместе.
Как задать условие, чтобы выделить строки списка цветом?
Кодом это делать не обязательно. Откройте настройки списка или отчёта, вкладку Условное оформление, добавьте элемент: задайте оформление (цвет, шрифт), условие по полю и колонки, к которым применить. Платформа подсветит строки сама.