Условия ВЫБОР КОГДА ТОГДА в запросах 1С: от синтаксиса до периодов и СКД
Содержание
Оператор КОГДА в языке запросов 1С работает только внутри конструкции ВЫБОР КОГДА <условие> ТОГДА <значение> ИНАЧЕ <значение> КОНЕЦ (по-английски CASE WHEN ... THEN ... ELSE ... END). Она вычисляет значение поля по условию прямо в запросе: разносит документы по срокам, превращает дату в «просрочено / в срок», делит суммы на колонки.
С датами КОГДА почти всегда работает в паре с функциями НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА, РАЗНОСТЬДАТ и ДОБАВИТЬКДАТЕ. Ниже — синтаксис, рабочие примеры, влияние на скорость, применение в СКД и ошибки, на которых спотыкаются чаще всего.
Как устроена конструкция ВЫБОР КОГДА
Общая форма:
ВЫБОР
КОГДА <условие 1> ТОГДА <выражение 1>
КОГДА <условие 2> ТОГДА <выражение 2>
ИНАЧЕ <выражение по умолчанию>
КОНЕЦ КАК ИмяПоля
Правила, которые нужно держать в голове:
- 🔹 Веток
КОГДАможет быть сколько угодно. Платформа проверяет их сверху вниз и берёт первую истинную. Остальные уже не важны. - 🔹
ИНАЧЕнеобязательно. Если его нет и ни одно условие не сработало, результат —NULL. - 🔹 После
КОГДАстоит логическое выражение: сравнение,ЕСТЬ NULL,В (...),МЕЖДУ,ПОДОБНО,ССЫЛКА. Короткой формы «ВЫБОР Поле КОГДА 1 ТОГДА…», как в некоторых диалектах SQL, в языке запросов 1С нет — каждое условие пишется полностью:КОГДА Поле = 1. - 🔹 Конструкция заканчивается словом
КОНЕЦ. Псевдоним черезКАКставится после него. - 🔹 Использовать её можно в списке полей
ВЫБРАТЬ, вГДЕ, вСГРУППИРОВАТЬ ПО, вУПОРЯДОЧИТЬ ПО, внутри агрегатных функций и в условиях соединения.
Простейший пример — признак проведённого документа текстом:
ВЫБРАТЬ
Реализация.Ссылка,
ВЫБОР
КОГДА Реализация.Проведен
ТОГДА "Проведён"
ИНАЧЕ "Не проведён"
КОНЕЦ КАК Состояние
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
Здесь Реализация.Проведен уже имеет тип «Булево», поэтому писать = ИСТИНА не нужно.
Тип результата
Все ветки ТОГДА и ИНАЧЕ лучше приводить к одному типу. Если одна ветка возвращает число, а другая строку, поле получит составной тип. Такое поле неудобно сортировать и суммировать, а в СКД оно не станет ресурсом.
| Задача | Как писать ветки |
|---|---|
| Числовая колонка для суммы | ТОГДА Сумма ИНАЧЕ 0 |
| Текстовая метка | Все ветки — строковые литералы |
| Ссылка | Все ветки — ссылки одного типа, пустая — через ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) |
| Дата | Все ветки — даты, пустая — ДАТАВРЕМЯ(1, 1, 1) |
Условия по датам: начало и конец периодов
Даты в запросе хранятся с точностью до секунды. Поэтому сравнение «документ за 31 марта» через Дата = ДАТАВРЕМЯ(2025, 3, 31) найдёт только документы ровно на 00:00:00. Почти всегда дату сначала обрезают до границы периода.
Функции, которые нужны вместе с КОГДА
| Функция | Что возвращает | Пример |
|---|---|---|
НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) | Первое число месяца, 00:00:00 | 01.03 00:00:00 |
КОНЕЦПЕРИОДА(Дата, МЕСЯЦ) | Последнее число месяца, 23:59:59 | 31.03 23:59:59 |
ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, 30) | Дата, сдвинутая на 30 дней | — |
РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) | Число единиц от Даты1 до Даты2 | 45 |
ГОД(), КВАРТАЛ(), МЕСЯЦ(), ДЕНЬМЕСЯЦА() | Часть даты числом | 2025, 1, 3, 31 |
ДЕНЬНЕДЕЛИ(Дата) | 1 — понедельник … 7 — воскресенье | 6 |
ДАТАВРЕМЯ(2025, 3, 31) | Литерал даты | — |
Периоды для НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА: МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, ДЕКАДА, МЕСЯЦ, КВАРТАЛ, ПОЛУГОДИЕ, ГОД. У РАЗНОСТЬДАТ набор короче: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД.
Функции ТЕКУЩАЯДАТА() в языке запросов нет. Текущую дату или дату отчёта передают параметром: Запрос.УстановитьПараметр("ДатаОтчета", ТекущаяДатаСеанса()); и в тексте пишут &ДатаОтчета.
Пример 1. Метка «текущий месяц / прошлые периоды»
ВЫБРАТЬ
Док.Ссылка,
ВЫБОР
КОГДА Док.Дата >= НАЧАЛОПЕРИОДА(&ДатаОтчета, МЕСЯЦ)
ТОГДА "Текущий месяц"
КОГДА Док.Дата >= НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаОтчета, МЕСЯЦ, -1), МЕСЯЦ)
ТОГДА "Прошлый месяц"
ИНАЧЕ "Ранее"
КОНЕЦ КАК Период
ИЗ
Документ.ПоступлениеТоваровУслуг КАК Док
ГДЕ
Док.Дата <= КОНЕЦПЕРИОДА(&ДатаОтчета, ДЕНЬ)
Вторая ветка не проверяет верхнюю границу. Она не нужна: документы текущего месяца уже забрала первая ветка, а порядок проверки строго сверху вниз.
Пример 2. Возраст задолженности по корзинам
Классическая задача — разложить документы по срокам: до 30 дней, 31–60, 61–90 и больше.
ВЫБРАТЬ
Долги.Контрагент,
Долги.Документ,
Долги.Сумма,
ВЫБОР
КОГДА РАЗНОСТЬДАТ(Долги.ДатаДокумента, &ДатаОтчета, ДЕНЬ) <= 30
ТОГДА "1. до 30 дней"
КОГДА РАЗНОСТЬДАТ(Долги.ДатаДокумента, &ДатаОтчета, ДЕНЬ) <= 60
ТОГДА "2. 31–60 дней"
КОГДА РАЗНОСТЬДАТ(Долги.ДатаДокумента, &ДатаОтчета, ДЕНЬ) <= 90
ТОГДА "3. 61–90 дней"
ИНАЧЕ "4. более 90 дней"
КОНЕЦ КАК СрокДолга
ИЗ
ВТ_Долги КАК Долги
Цифры в начале меток — простой приём, чтобы сортировка по полю СрокДолга шла в нужном порядке, а не по алфавиту. Проверка на числах: документ от 01.03, дата отчёта 15.04 — разница 45 дней, попадает во вторую корзину.
Если в дате документа есть время, а в &ДатаОтчета — конец дня, результат на границе может «прыгнуть» на день. Чтобы считать в целых днях, оберните обе даты: РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Долги.ДатаДокумента, ДЕНЬ), НАЧАЛОПЕРИОДА(&ДатаОтчета, ДЕНЬ), ДЕНЬ).
Пример 3. Выходные и рабочие дни
ВЫБОР
КОГДА ДЕНЬНЕДЕЛИ(Док.Дата) В (6, 7)
ТОГДА "Выходной"
ИНАЧЕ "Будний"
КОНЕЦ КАК ТипДня
Праздники так не определить — для них нужен производственный календарь , соединённый с запросом по дате.
Пример 4. Пустая дата
Незаполненная дата в 1С — это ДАТАВРЕМЯ(1, 1, 1), а не NULL. NULL появляется, только если поле пришло из левого соединения и записи справа нет. Надёжная проверка закрывает оба случая:
ВЫБОР
КОГДА Оплаты.ДатаОплаты ЕСТЬ NULL
ИЛИ Оплаты.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА "Не оплачено"
КОГДА Оплаты.ДатаОплаты > Заказы.СрокОплаты
ТОГДА "Оплачено с опозданием"
ИНАЧЕ "Оплачено в срок"
КОНЕЦ КАК СтатусОплаты
Скорость запроса: где КОГДА помогает, а где тормозит
Сама конструкция ВЫБОР в списке полей почти ничего не стоит: СУБД вычисляет её для уже отобранных строк. Проблемы начинаются, когда она попадает туда, где СУБД выбирает строки.
| Где стоит ВЫБОР | Влияние на скорость | Что делать |
|---|---|---|
Список полей ВЫБРАТЬ | Минимальное | Ничего |
Внутри СУММА(...) | Минимальное, часто быстрее нескольких запросов | Использовать смело |
ГДЕ по индексированному полю | Индекс не используется, идёт полный просмотр | Переписать через И / ИЛИ |
Условие СОЕДИНЕНИЕ ... ПО | Соединение без индекса, на больших таблицах — минуты | Вынести вычисление во временную таблицу и индексировать |
СГРУППИРОВАТЬ ПО | Умеренное | Допустимо |
Как переписать условие в ГДЕ
Плохо — индекс по дате не сработает:
ГДЕ
ВЫБОР
КОГДА &ТолькоТекущийМесяц
ТОГДА Док.Дата >= НАЧАЛОПЕРИОДА(&ДатаОтчета, МЕСЯЦ)
ИНАЧЕ ИСТИНА
КОНЕЦ
Лучше — та же логика обычными операторами:
ГДЕ
(НЕ &ТолькоТекущийМесяц
ИЛИ Док.Дата >= &НачалоМесяца)
Параметр &НачалоМесяца вычислите заранее во встроенном языке: НачалоМесяца(ТекущаяДатаСеанса()). Тогда справа от сравнения стоит готовая константа, и СУБД может пойти по индексу.
Функции над полем (НАЧАЛОПЕРИОДА(Док.Дата, МЕСЯЦ) = &Месяц) тоже мешают индексу. Для отбора пишите диапазон: Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода. А вот в списке полей функции над датой безопасны.
Сумма по условию вместо нескольких запросов
Частый приём — развернуть строки в колонки одной выборкой:
ВЫБРАТЬ
Продажи.Номенклатура,
СУММА(ВЫБОР
КОГДА Продажи.Период < &НачалоМесяца
ТОГДА Продажи.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК ДоНачалаМесяца,
СУММА(ВЫБОР
КОГДА Продажи.Период >= &НачалоМесяца
ТОГДА Продажи.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК ЗаМесяц
ИЗ
ВТ_Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Номенклатура
Одна таблица читается один раз, а не дважды через объединение.
Вложенные ВЫБОР и сложные условия
Внутри ТОГДА и ИНАЧЕ может стоять ещё один ВЫБОР. Это удобно, когда вторая проверка имеет смысл только для части строк.
ВЫБОР
КОГДА Заказы.Закрыт
ТОГДА "Закрыт"
ИНАЧЕ
ВЫБОР
КОГДА Заказы.ДатаОтгрузки < &ДатаОтчета
ТОГДА "Просрочен"
КОГДА Заказы.ДатаОтгрузки <= ДОБАВИТЬКДАТЕ(&ДатаОтчета, ДЕНЬ, 3)
ТОГДА "Срок через 1–3 дня"
ИНАЧЕ "В работе"
КОНЕЦ
КОНЕЦ КАК Статус
Каждый вложенный ВЫБОР закрывается своим КОНЕЦ. Пропущенный КОНЕЦ — самая частая причина синтаксической ошибки в длинных запросах.
Часто вложенность можно убрать, объединив условия через И:
ВЫБОР
КОГДА Заказы.Закрыт ТОГДА "Закрыт"
КОГДА Заказы.ДатаОтгрузки < &ДатаОтчета ТОГДА "Просрочен"
КОГДА Заказы.ДатаОтгрузки <= ДОБАВИТЬКДАТЕ(&ДатаОтчета, ДЕНЬ, 3) ТОГДА "Срок через 1–3 дня"
ИНАЧЕ "В работе"
КОНЕЦ КАК Статус
Результат тот же: закрытые заказы отсекает первая ветка. Плоский вариант читается легче, вложенный оставляйте, когда внутренняя часть повторяется в нескольких местах или сильно отличается по смыслу.
Условие по типу ссылки
Поле Регистратор и другие составные поля проверяют через ССЫЛКА:
ВЫБОР
КОГДА Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ТОГДА ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент
КОГДА Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
ТОГДА ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Контрагент
КОНЕЦ КАК Контрагент
ВЫРАЗИТЬ здесь важен. Обращение Движения.Регистратор.Контрагент без него заставит платформу соединить таблицы всех типов документов-регистраторов, и запрос заметно замедлится.
ВЫБОР КОГДА в системе компоновки данных
В СКД конструкция встречается в трёх местах.
1. В тексте запроса набора данных. Работает так же, как в обычном запросе. Параметры вида &ДатаОтчета СКД сама выведет на вкладку «Параметры», где им можно задать значение по умолчанию или выражение.
2. В вычисляемых полях. На вкладке «Вычисляемые поля» в колонке «Выражение» допускается ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ. Это выражение языка компоновки, а не запроса: оно считается после получения данных, по полям набора. Удобно, когда метку нужно строить из полей разных наборов.
3. В выражениях ресурсов. На вкладке «Ресурсы» можно задать, например:
Сумма(ВЫБОР КОГДА СрокДолга = "4. более 90 дней" ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ)
Ресурс посчитается на каждом уровне группировки.
| Где считать | Плюсы | Минусы |
|---|---|---|
| В запросе набора | Отбор и группировку делает СУБД, быстро | Нужно править текст запроса |
| Вычисляемое поле | Видно в настройках, легко поменять | Считается на сервере 1С по каждой строке |
| Выражение ресурса | Итоги по группировкам «из коробки» | Только для агрегатов |
Отбор пользователя по вычисляемому полю СКД не может передать в запрос. Сначала читаются все строки, потом фильтр применяется в памяти. Если по полю будут часто отбирать, считайте его в запросе набора.
Для группировки по месяцам в СКД обычно не нужен ВЫБОР: у виртуальных таблиц регистров есть поля ПериодМесяц, ПериодКвартал и подобные, если в параметрах таблицы указана периодичность Авто. ВЫБОР по дате нужен для нестандартных корзин: «до 30 дней», «текущий / прошлый квартал», «выходной / будний».
Частые ошибки с КОГДА в запросах 1С
Ещё одна ловушка — группировка. В СГРУППИРОВАТЬ ПО нельзя сослаться на псевдоним поля, выражение ВЫБОР нужно повторить целиком. В УПОРЯДОЧИТЬ ПО псевдоним использовать можно. Чтобы не дублировать длинную конструкцию, посчитайте её во временной таблице и группируйте уже по готовому полю.
И порядок веток. Условие РАЗНОСТЬДАТ(...) <= 90, поставленное первым, заберёт и 10-дневные, и 50-дневные долги. Корзины по возрастанию или убыванию всегда идут от самой узкой к самой широкой.
Частые вопросы
Можно ли использовать английский синтаксис CASE WHEN в запросе 1С?
Есть ли в языке запросов 1С аналог функции ЕСЛИ из встроенного языка?
?(...) в запросах не работает. Любое условное значение пишется через ВЫБОР КОГДА.