Оператор «Когда в» (или `WHEN IN` в английской нотации) — один из самых гибких инструментов в языке запросов 1С:Предприятие, но его синтаксис часто вызывает вопросы даже у опытных разработчиков. Он позволяет проверять принадлежность значения к набору элементов, что особенно полезно при работе со справочниками, перечислениями или массивами данных. Однако неправильное использование этого оператора может привести к ошибкам выполнения, медленным запросам или некорректной выборке.

В этой статье разберём все нюансы работы с «Когда в»: от базового синтаксиса до оптимизации сложных условий. Вы узнаете, как избежать типичных ошибок, когда лучше заменить его на альтернативные конструкции, и как использовать оператор для динамических списков (например, при выборке по нескольким значениям справочника). Особое внимание уделим производительности — ведь неправильно составленный запрос с `WHEN IN` может тормозить систему даже на небольших базах.

Если вы только начинаете осваивать язык запросов 1С, этот материал поможет разобраться в логике работы оператора. Опытным разработчикам пригодятся практические примеры и сравнение с аналогами (например, `В` или `ПОДОБНО`), а также советы по оптимизации.

Что такое оператор «Когда в» и зачем он нужен

Оператор «Когда в» (или `WHEN IN` в английской версии платформы) используется в языке запросов 1С:Предприятие для проверки, содержится ли значение в заданном наборе. По сути, это аналог конструкции `IN` в SQL, но с специфическим синтаксисом 1С.

Основное назначение оператора:

  • 📌 Фильтрация данных по нескольким значениям (например, выборка документов только по определённым контрагентам).
  • 🔄 Замена множества условий `ИЛИ` — вместо ГДЕ Контрагент = Значение1 ИЛИ Контрагент = Значение2 можно написать ГДЕ Контрагент В (&СписокКонтрагентов).
  • 📊 Работа с динамическими списками — когда набор значений формируется программно (например, из массива или результата другого запроса).

Пример базового использования:

ВЫБРАТЬ

Номенклатура.Наименование,

Номенклатура.Артикул

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.ВидНоменклатуры В (&ВидыНоменклатуры)

Здесь `&ВидыНоменклатуры` — параметр запроса, который может содержать массив значений.

Важно понимать, что «Когда в» работает не только со справочниками, но и с любыми типами данных, поддерживающими сравнение: строки, числа, даты, перечисления. Однако есть нюансы — например, с составными типами (как Ссылка.Объект) или NULL-значениями.

📊 Как часто вы используете оператор "Когда в" в запросах 1С?
Постоянно
Иногда
Редеко
Никогда

Синтаксис оператора: как правильно писать

Общий синтаксис оператора выглядит так:

ВЫРАЖЕНИЕ [НЕ] В (ЗНАЧЕНИЕ1, ЗНАЧЕНИЕ2, ..., ЗНАЧЕНИЕN)

Где:

- `ВЫРАЖЕНИЕ` — поле или выражение, которое проверяется.

- `НЕ` — опциональный оператор отрицания (аналог `NOT IN` в SQL).

- `(ЗНАЧЕНИЕ1, ЗНАЧЕНИЕ2, ...)` — список значений для проверки.

Примеры корректного использования:

  • 🔹 ГДЕ Контрагент В (&СписокКонтрагентов) — проверка по параметру-запроса.
  • 🔹 ГДЕ Дата ДОБАВИТЬ К ДАТЕ(ДАТАВРЕМЯ(2023,1,1), МЕСЯЦ, 1) В (ДАТАВРЕМЯ(2023,2,1), ДАТАВРЕМЯ(2023,3,1)) — проверка дат.
  • 🔹 ГДЕ НЕ ВидДокумента В (Значение(Перечисление.ВидыДокументов.ПриходныйОрдер)) — исключение определённых видов.

Важно! Если список значений пуст, запрос с `В` вернёт пустой результат, а с `НЕ В` — все строки (аналогично SQL). Это частая причина ошибок при динамическом формировании условий.

Также оператор поддерживает вложенные запросы в качестве источника значений:

ГДЕ Контрагент В (ВЫБРАТЬ Контрагенты.Ссылка ИЗ Справочник.Контрагенты КАК Контрагенты)

Но такой подход может значительно замедлить выполнение на больших базах — лучше использовать временные таблицы или объединения (`СОЕДИНИТЬ`).

💡

Если список значений для "Когда в" формируется программно, всегда проверяйте его на пустоту перед выполнением запроса. Пустой массив приведёт к неожиданным результатам!

«Когда в» vs альтернативные операторы: что выбрать

В языке запросов 1С есть несколько способов фильтрации по набору значений. Рассмотрим, когда лучше использовать «Когда в», а когда — альтернативы.

Оператор Пример использования Плюсы Минусы
Когда в (В) ГДЕ Город В (&СписокГородов) ✅ Компактный синтаксис
✅ Поддерживает динамические списки
❌ Медленнее на больших наборах данных
❌ Не оптимизируется сервером 1С
Множество условий ИЛИ ГДЕ Город = "Москва" ИЛИ Город = "СПб" ✅ Быстрее при малом количестве значений
✅ Лучше читается для статических списков
❌ Громоздко при большом количестве условий
Соединение (СОЕДИНИТЬ) СОЕДИНИТЬ Справочник.Города КАК Города ПО Город.Ссылка = Документ.Город ✅ Оптимально для больших выборок
✅ Гибкость в условиях
❌ Сложнее в написании
❌ Требует дополнительных таблиц

Когда стоит выбрать «Когда в»?

  • 📋 Список значений формируется динамически (например, из массива или результата другого запроса).
  • 🔢 Количество значений не превышает 10–20 (иначе лучше использовать СОЕДИНИТЬ).
  • 📌 Нужно быстро написать простой запрос без оптимизации.

Когда лучше избегать «Когда в»?

  • 🐢 Работа с большими таблицами (более 100 000 строк).
  • 🔄 Нужна максимальная производительность (например, в отчётах с большим объёмом данных).
  • 📊 Список значений очень большой (сотни или тысячи элементов).
💡

Для статических списков из 2–3 значений лучше использовать цепочку "ИЛИ" — это ускорит выполнение запроса.

Типичные ошибки при использовании «Когда в»

Даже опытные разработчики иногда допускают ошибки при работе с «Когда в». Рассмотрим самые распространённые из них и как их избежать.

1. Пустой список значений

Если параметр, передаваемый в `В`, оказывается пустым, запрос вернёт пустой результат (даже если в таблице есть данные). Например:

&СписокКонтрагентов = Новый Массив(); // Пустой массив

Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Контрагент В (&СписокКонтрагентов)";

⚠️ Внимание: Всегда проверяйте параметры на пустоту перед выполнением запроса. Например, так:
ЕСЛИ &СписокКонтрагентов.Количество() = 0 ТОГДА

Возврат Новый ТаблицаЗначений;

КОНЕЦЕСЛИ;

2. Несовпадение типов данных

Если типы сравниваемых значений не совпадают, 1С может не выдавать ошибку, но результат будет некорректным. Например:

ГДЕ ЧисловоеПоле В ("10", "20") // Сравниваем число со строками!

Решение: приведите типы к одному виду с помощью `ЗНАЧЕНИЕ()` или `ЧИСЛО()`.

3. Использование с NULL

Оператор `В` не учитывает `NULL`-значения. Если в списке есть `NULL`, они будут проигнорированы. Например:

ГДЕ Поле В (NULL, 10, 20) // NULL не будет учтён!

Для проверки на `NULL` используйте отдельное условие:

ГДЕ (Поле В (10, 20) ИЛИ Поле ЕСТЬ NULL)

4. Избыточные условия

Иногда разработчики комбинируют `В` с другими операторами без необходимости. Например:

ГДЕ (Контрагент В (&Список) И Контрагент.Наименование НАЧИНАЕТСЯ С "А")

Это может привести к полному сканированию таблицы (table scan) и замедлению запроса. Лучше разделить условия или использовать индексы.

Что будет, если передать в "Когда в" массив с разными типами данных?

Если в массиве смешаны, например, числа и строки, 1С попытается привести их к общему типу. Это может привести к ошибке или неявному приведению (например, строка "123" будет преобразована в число 123). Всегда следите за типами данных в параметрах!

Оптимизация запросов с «Когда в»

Запросы с оператором «Когда в» могут работать медленно, если не учитывать особенности платформы 1С. Вот несколько способов их оптимизировать:

1. Используйте временные таблицы

Если список значений большой (более 20 элементов), лучше загрузить его во временную таблицу и использовать `СОЕДИНИТЬ`:

// Создаём временную таблицу

ВТ_Контрагенты = Новый ВременнаяТаблица;

ВТ_Контрагенты.ДобавитьКолонку("Ссылка");

// Заполняем данными

Для Каждого Контрагент Из &СписокКонтрагентов Цикл

Строка = ВТ_Контрагенты.Добавить();

Строка.Ссылка = Контрагент;

КонецЦикла;

// Используем в запросе

Запрос.Текст = "

ВЫБРАТЬ ...

СОЕДИНИТЬ ВТ_Контрагенты КАК ВТ

ПО Документ.Контрагент = ВТ.Ссылка";

2. Применяйте индексы

Если поле, по которому идёт фильтрация, не проиндексировано, запрос будет выполняться дольше. Проверьте наличие индексов в конфигураторе (раздел «Индексы» для справочников и документов).

3. Разбивайте сложные условия

Если в запросе много условий с `В`, попробуйте разбить его на несколько более простых запросов с объединением результатов (ОБЪЕДИНИТЬ ВСЕ).

4. Избегайте вложенных запросов

Конструкции вида:

ГДЕ Поле В (ВЫБРАТЬ Поле2 ИЗ Таблица2)

могут сильно тормозить. Замените их на временные таблицы или предварительную выборку.

Проверить список значений на пустоту

Убедиться в совпадении типов данных

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

Добавить индексы на фильтруемые поля

Разбить сложные условия на простые запросы-->

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

Рассмотрим несколько реальных сценариев, где «Когда в» оказывается полезным.

Пример 1: Выборка документов по нескольким контрагентам

Допустим, нам нужно получить все документы «РеализацияТоваровУслуг» для конкретного списка контрагентов:

ВЫБРАТЬ

Документ.Ссылка КАК Ссылка,

Документ.Дата КАК Дата,

Документ.СуммаДокумента КАК Сумма

ИЗ

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

ГДЕ

Документ.Контрагент В (&СписокКонтрагентов)

И Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

УПОРЯДОЧИТЬ ПО

Документ.Дата УБЫВ

Пример 2: Фильтрация по перечислению

Если нужно выбрать номенклатуру только определённых видов (из перечисления):

ВЫБРАТЬ

Номенклатура.Наименование,

Номенклатура.Артикул

ИЗ

Справочник.Номенклатура КАК Номенклатура

ГДЕ

Номенклатура.ВидНоменклатуры В (

Значение(Перечисление.ВидыНоменклатуры.Товар),

Значение(Перечисление.ВидыНоменклатуры.Услуга)

)

Пример 3: Динамический список из массива

Если список значений формируется в коде:

&МассивВидов = Новый Массив;

&МассивВидов.Добавить(Значение(Перечисление.ВидыДокументов.ПриходныйОрдер));

&МассивВидов.Добавить(Значение(Перечисление.ВидыДокументов.РасходныйОрдер));

Запрос.Текст = "

ВЫБРАТЬ ...

ГДЕ ВидДокумента В (&МассивВидов)";

Пример 4: Исключение значений (`НЕ В`)

Чтобы выбрать все документы, кроме определённых видов:

ГДЕ ВидДокумента НЕ В (

Значение(Перечисление.ВидыДокументов.КорректировкаДолга),

Значение(Перечисление.ВидыДокументов.Инвентаризация)

)

💡

Если список значений для "НЕ В" содержит NULL, используйте конструкцию "ИЛИ Поле ЕСТЬ NULL", иначе NULL-значения не будут исключены!

Особенности работы с разными типами данных

Оператор «Когда в» ведёт себя по-разному в зависимости от типа данных. Разберём ключевые нюансы.

1. Работа со справочниками и документами

При фильтрации по ссылкам (например, `Контрагент`, `Номенклатура`) важно передавать в запрос именно ссылки, а не строковые представления. Например:

// Правильно:

&СписокКонтрагентов.Добавить(Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка").Ссылка);

// Неправильно (может не сработать):

&СписокКонтрагентов.Добавить("ООО Ромашка");

2. Строки и регистр

При сравнении строк учитывается регистр! Например:

ГДЕ Город В ("Москва", "питер") // "Питер" и "питер" — разные значения!

Для регистронезависимого поиска используйте `ВЕРХНИЙРЕГ`:

ГДЕ ВЕРХНИЙРЕГ(Город) В ("МОСКВА", "ПИТЕР")

3. Даты и время

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

ГДЕ ДатаДокумента В (ДАТАВРЕМЯ(2023,01,01), ДАТАВРЕМЯ(2023,01,15))

Если нужно сравнить только дату без времени, используйте `НАЧАЛОДНЯ()`:

ГДЕ НАЧАЛОДНЯ(ДатаДокумента) В (ДАТАВРЕМЯ(2023,01,01), ДАТАВРЕМЯ(2023,01,15))

4. Числа и диапазоны

Для числовых полей «Когда в» менее эффективен, чем диапазоны (МЕЖДУ). Например:

// Медленнее:

ГДЕ Сумма В (1000, 2000, 3000, 4000, 5000)

// Быстрее:

ГДЕ Сумма МЕЖДУ 1000 И 5000

⚠️ Внимание: При работе с дробными числами (например, 10.5) следите за точностью сравнения. В 1С числа с плавающей запятой могут сравниваться с погрешностью. Для критичных расчётов используйте округление (ОКРУГЛ(Сумма, 2)).

FAQ: Ответы на частые вопросы

Можно ли использовать «Когда в» с подзапросами?

Да, но это не рекомендуется для больших баз данных. Например:

ГДЕ Поле В (ВЫБРАТЬ Поле2 ИЗ Таблица2)

Такой запрос может тормозить, так как 1С не оптимизирует вложенные подзапросы в условии `В`. Лучше использовать временные таблицы или объединения.

Почему запрос с «Когда в» возвращает пустой результат, хотя данные есть?

Наиболее вероятные причины:

  • 🔸 Параметр со списком значений пуст.
  • 🔸 Типы данных не совпадают (например, сравниваете число со строкой).
  • 🔸 В списке есть NULL, но вы не учли это в условии.
  • 🔸 Поле не проиндексировано, и запрос выполняется слишком долго (прерывается по таймауту).

Проверьте каждый пункт по порядку.

Как передать в «Когда в» данные из массива или таблицы значений?

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

&Массив = Новый Массив;

&Массив.Добавить(Справочники.Номенклатура.Товар1);

&Массив.Добавить(Справочники.Номенклатура.Товар2);

Запрос.УстановитьПараметр("Список", &Массив);

Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Номенклатура В (&Список)";

Для таблицы значений сначала извлеките данные в массив:

&Массив = Новый Массив;

Для Каждого Строка Из &Таблица Цикл

&Массив.Добавить(Строка.Ссылка);

КонецЦикла;

Можно ли использовать «Когда в» с полями типа «Булево»?

Технически да, но это бессмысленно, так как у булевого поля только два значения: `Истина` и `Ложь`. Например:

ГДЕ Флаг В (Истина) // Эквивалентно ГДЕ Флаг = Истина

Для булевых полей лучше использовать простые условия:

ГДЕ Флаг = Истина
Как ускорить запрос с «Когда в» на большой базе?

Вот несколько способов:

  • 🚀 Замените `В` на `СОЕДИНИТЬ` с временной таблицей.
  • 🔍 Добавьте индексы на поля, по которым идёт фильтрация.
  • 📊 Разбейте запрос на несколько более простых с `ОБЪЕДИНИТЬ ВСЕ`.
  • 🔄 Если список значений большой, используйте пакетные запросы (выполняйте выборку порциями).

Также проверьте, не загружаете ли вы лишние поля в результат запроса — это может замедлять выполнение.