Оператор «Когда в» (или `WHEN IN` в английской нотации) — один из самых гибких инструментов в языке запросов 1С:Предприятие, но его синтаксис часто вызывает вопросы даже у опытных разработчиков. Он позволяет проверять принадлежность значения к набору элементов, что особенно полезно при работе со справочниками, перечислениями или массивами данных. Однако неправильное использование этого оператора может привести к ошибкам выполнения, медленным запросам или некорректной выборке.
В этой статье разберём все нюансы работы с «Когда в»: от базового синтаксиса до оптимизации сложных условий. Вы узнаете, как избежать типичных ошибок, когда лучше заменить его на альтернативные конструкции, и как использовать оператор для динамических списков (например, при выборке по нескольким значениям справочника). Особое внимание уделим производительности — ведь неправильно составленный запрос с `WHEN IN` может тормозить систему даже на небольших базах.
Если вы только начинаете осваивать язык запросов 1С, этот материал поможет разобраться в логике работы оператора. Опытным разработчикам пригодятся практические примеры и сравнение с аналогами (например, `В` или `ПОДОБНО`), а также советы по оптимизации.
Что такое оператор «Когда в» и зачем он нужен
Оператор «Когда в» (или `WHEN IN` в английской версии платформы) используется в языке запросов 1С:Предприятие для проверки, содержится ли значение в заданном наборе. По сути, это аналог конструкции `IN` в SQL, но с специфическим синтаксисом 1С.
Основное назначение оператора:
- 📌 Фильтрация данных по нескольким значениям (например, выборка документов только по определённым контрагентам).
- 🔄 Замена множества условий `ИЛИ` — вместо
ГДЕ Контрагент = Значение1 ИЛИ Контрагент = Значение2можно написатьГДЕ Контрагент В (&СписокКонтрагентов). - 📊 Работа с динамическими списками — когда набор значений формируется программно (например, из массива или результата другого запроса).
Пример базового использования:
ВЫБРАТЬ
Номенклатура.Наименование,
Номенклатура.Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ВидНоменклатуры В (&ВидыНоменклатуры)
Здесь `&ВидыНоменклатуры` — параметр запроса, который может содержать массив значений.
Важно понимать, что «Когда в» работает не только со справочниками, но и с любыми типами данных, поддерживающими сравнение: строки, числа, даты, перечисления. Однако есть нюансы — например, с составными типами (как Ссылка.Объект) или NULL-значениями.
Синтаксис оператора: как правильно писать
Общий синтаксис оператора выглядит так:
ВЫРАЖЕНИЕ [НЕ] В (ЗНАЧЕНИЕ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);
Запрос.УстановитьПараметр("Список", &Массив);
Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Номенклатура В (&Список)";
Для таблицы значений сначала извлеките данные в массив:
&Массив = Новый Массив;
Для Каждого Строка Из &Таблица Цикл
&Массив.Добавить(Строка.Ссылка);
КонецЦикла;
Можно ли использовать «Когда в» с полями типа «Булево»?
Технически да, но это бессмысленно, так как у булевого поля только два значения: `Истина` и `Ложь`. Например:
ГДЕ Флаг В (Истина) // Эквивалентно ГДЕ Флаг = Истина
Для булевых полей лучше использовать простые условия:
ГДЕ Флаг = Истина
Как ускорить запрос с «Когда в» на большой базе?
Вот несколько способов:
- 🚀 Замените `В` на `СОЕДИНИТЬ` с временной таблицей.
- 🔍 Добавьте индексы на поля, по которым идёт фильтрация.
- 📊 Разбейте запрос на несколько более простых с `ОБЪЕДИНИТЬ ВСЕ`.
- 🔄 Если список значений большой, используйте пакетные запросы (выполняйте выборку порциями).
Также проверьте, не загружаете ли вы лишние поля в результат запроса — это может замедлять выполнение.