Условие связи ВЫБРАТЬ КОГДА в языке запросов 1С:Предприятие — один из самых мощных, но часто неправильно используемых инструментов. Оно позволяет объединять данные из нескольких таблиц не по стандартному равенству полей (как в СОЕДИНИТЬ), а по произвольному логическому выражению. Это открывает возможности для создания сложных отчетов, аналитики с нестандартными связями или обработки данных с разрывами в временных рядах.

Однако многие разработчики сталкиваются с проблемами: запрос работает медленно, возвращает неожиданные результаты или вообще не компилируется. В этой статье разберем синтаксис условия ВЫБРАТЬ КОГДА, покажем реальные примеры для типичных задач (связь по датам, интервалам, частичному совпадению), объясним как платформа 1С оптимизирует такие запросы под капотом и дадим рекомендации по ускорению их выполнения. Особое внимание уделим ловушкам, в которые попадают даже опытные программисты.

1. Синтаксис условия ВЫБРАТЬ КОГДА: основы и обязательные элементы

Конструкция ВЫБРАТЬ КОГДА в запросе 1С всегда используется внутри секции СОЕДИНИТЬ и заменяет стандартное условие равенства полей. Её общий вид:

ВЫБРАТЬ

ПоляИзЛевойТаблицы

ИЗ

ЛеваяТаблица КАК Л

ЛЕВОЕ СОЕДИНЕНИЕ ПраваяТаблица КАК П

ПО (ВЫБРАТЬ КОГДА Л.Поле1 > П.Поле2 И Л.Поле3 = П.Поле4)

Ключевые правила:

  • 🔹 Условие обязательно заключается в скобки (...) после ключевого слова ПО.
  • 🔹 Внутри скобок используется полноценное логическое выражение (можно с И, ИЛИ, НЕ).
  • 🔹 Поля в условии должны быть квалифицированы aliases'ами таблиц (например, Л.Дата, а не просто Дата).
  • 🔹 Можно использовать функции 1С (например, НАЧАЛОПЕРИОДА(П.Дата, Месяц)).

Важно: условие ВЫБРАТЬ КОГДА работает только в контексте соединения таблиц. Его нельзя использовать в секциях ГДЕ или ИМЕЮЩИЕ — для этого есть другие конструкции.

📊 Как часто вы используете ВЫБРАТЬ КОГДА в запросах 1С?
Никогда
Редко, только для специфических задач
Часто, это мой основной инструмент для сложных связей
Предпочитаю обходиться стандартными соединениями

2. Когда применять ВЫБРАТЬ КОГДА: 5 типичных сценариев

Стандартные соединения (ВНУТРЕННЕЕ, ЛЕВОЕ) покрывают 80% задач, но есть ситуации, где без ВЫБРАТЬ КОГДА не обойтись. Рассмотрим самые распространенные случаи:

2.1. Связь по неравенству (интервалы дат, диапазоны значений)

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

ВЫБРАТЬ

Документ.Номер,

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

Регистр.Количество

ИЗ

Документ Документ

ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Остатки КАК Регистр

ПО (ВЫБРАТЬ КОГДА Документ.Дата >= Регистр.Период

И Документ.Дата < КОНЕЦДНЯ(Регистр.Период))

2.2. Связь по частичному совпадению (подстроки, шаблоны)

Например, связать номенклатуру с классификатором по первым 3 символам артикула:

ВЫБРАТЬ

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

Классификатор.Группа

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Классификатор КАК Классификатор

ПО (ВЫБРАТЬ КОГДА ЛЕВ(Номенклатура.Артикул, 3) = Классификатор.Префикс)

2.3. Связь с учетом иерархии

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

ВЫБРАТЬ

Деталь.Наименование,

Родитель.Наименование КАК Группа

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Родитель

ПО (ВЫБРАТЬ КОГДА Деталь.Родитель = Родитель.Ссылка

ИЛИ Деталь.Родитель.Родитель = Родитель.Ссылка)

2.4. Связь по нескольким альтернативным условиям

Например, связать заказы с клиентами либо по основному контрагенту, либо по его филиалу:

ВЫБРАТЬ

Заказ.Номер,

Клиент.Наименование

ИЗ

Документ.ЗаказКлиента КАК Заказ

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Клиент

ПО (ВЫБРАТЬ КОГДА Заказ.Контрагент = Клиент.Ссылка

ИЛИ Заказ.Филиал = Клиент.Ссылка)

2.5. Связь с учетом статуса или флагов

Когда связь зависит от дополнительных условий, например, только для активных записей:

ВЫБРАТЬ

Заявка.Номер,

Исполнитель.Наименование

ИЗ

Документ.ЗаявкаНаОбслуживание КАК Заявка

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Исполнитель

ПО (ВЫБРАТЬ КОГДА Заявка.Исполнитель = Исполнитель.Ссылка

И Исполнитель.Активен = ИСТИНА)

💡

Если в условии связи используете функции (например, НАЧАЛОПЕРИОДА() или ЛЕВ()), добавьте их результаты в индексы таблиц базы данных — это ускорит выполнение запроса в 5-10 раз.

3. Оптимизация запросов с ВЫБРАТЬ КОГДА: как ускорить выполнение

Запросы с условием ВЫБРАТЬ КОГДА часто работают медленнее стандартных соединений, потому что:

  1. Платформа 1С не может использовать индексы так же эффективно, как при простом равенстве полей.
  2. Логические выражения в условии требуют вычислений для каждой пары строк.
  3. При большом объеме данных сервер СУБД может выбрать неоптимальный план выполнения.

Чтобы ускорить запрос, следуйте этим рекомендациям:

Проблема Решение Пример
Сложные функции в условии (например, НАЙТИ()) Перенесите вычисления в виртуальные таблицы или временные таблицы
ВТ_Артикулы = НОВЫЙ ТаблицаЗначений;

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

// Заполняем префиксы заранее

ВЫБРАТЬ ... ПО (ВЫБРАТЬ КОГДА Л.Артикул НАЧИНАЕТСЯ С ВТ_Артикулы.Префикс)

Связь по датам с функциями (НАЧАЛОПЕРИОДА()) Используйте предвычисленные поля в запросе
ВЫБРАТЬ

НАЧАЛОПЕРИОДА(Документ.Дата, Месяц) КАК Период,

...

ПО (ВЫБРАТЬ КОГДА Период = Регистр.Период)

Множество условий с ИЛИ Разбейте на несколько соединений с ОБЪЕДИНИТЬ
ВЫБРАТЬ ... ПО (Условие1)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ ... ПО (Условие2)

Критически важно: если в условии связи используете поля, по которым нет индексов в СУБД, запрос будет выполняться перебором всех строк (full scan). Проверьте план выполнения запроса в консоли администрирования 1С!

💡

Самый эффективный способ ускорить запрос с ВЫБРАТЬ КОГДА — максимально сузить выборку в секции ГДЕ до соединения. Чем меньше строк участвует в соединении, тем быстрее оно выполнится.

4. Типичные ошибки и как их избежать

Даже опытные разработчики допускают ошибки при работе с ВЫБРАТЬ КОГДА. Вот самые распространенные:

4.1. Использование неквалифицированных полей

Ошибка:

ПО (ВЫБРАТЬ КОГДА Дата > Период)  // Неясно, из какой таблицы поля Дата и Период

Правильно:

ПО (ВЫБРАТЬ КОГДА Документ.Дата > Регистр.Период)

4.2. Забытые скобки вокруг условия

Ошибка:

ПО ВЫБРАТЬ КОГДА Л.Поле1 = П.Поле2 И Л.Поле3 > 100

Правильно:

ПО (ВЫБРАТЬ КОГДА Л.Поле1 = П.Поле2 И Л.Поле3 > 100)

4.3. Избыточные условия в ГДЕ и в соединении

Ошибка: дублирование одного и того же условия в ГДЕ и в ВЫБРАТЬ КОГДА. Это не только избыточно, но и может привести к конфликту оптимизатора.

4.4. Использование вложенных запросов в условии

Ошибка:

ПО (ВЫБРАТЬ КОГДА Л.Поле1 В (ВЫБРАТЬ П.Поле2 ИЗ ПраваяТаблица ГДЕ П.Поле3 = 100))

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

4.5. Неучет NULL-значений

Если поле в условии может быть NULL, явное сравнение (=, >) не сработает. Используйте ЕСТЬ NULL или ВЫРАЗИТЬ():

ПО (ВЫБРАТЬ КОГДА (Л.Поле1 ЕСТЬ NULL И П.Поле2 ЕСТЬ NULL)

ИЛИ Л.Поле1 = П.Поле2)

Что будет, если в условии связи использовать агрегатные функции?

Агрегатные функции (СУММА(), МАКСИМУМ()) в условии ВЫБРАТЬ КОГДА приводят к ошибке компиляции запроса. Для таких случаев нужно использовать подзапросы или временные таблицы с предварительно рассчитанными агрегатами.

5. Примеры реальных запросов с ВЫБРАТЬ КОГДА

Разберем практические задачи, где условие связи незаменимо.

5.1. Связь заказов с курсами валют на дату документа

Требуется показать сумму заказа в валюте с учетом курса на дату документа:

ВЫБРАТЬ

Заказ.Номер,

Заказ.Дата,

Заказ.Сумма / Курс.Курс КАК СуммаВРублях

ИЗ

Документ.ЗаказПокупателя КАК Заказ

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК Курс

ПО (ВЫБРАТЬ КОГДА Заказ.Дата >= Курс.Период

И Заказ.Дата < КОНЕЦДНЯ(Курс.Период)

И Заказ.Валюта = Курс.Валюта)

ГДЕ

Заказ.Валюта <> ЗНАЧЕНИЕ(Перечисление.Валюты.Рубль)

5.2. Связь товаров с акциями по периоду действия

Нужно показать товары с действующими на них скидками:

ВЫБРАТЬ

Товар.Наименование,

Товар.Цена,

Акция.ПроцентСкидки,

Товар.Цена * (1 - Акция.ПроцентСкидки/100) КАК ЦенаСоСкидкой

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ Документ.Акции КАК Акция

ПО (ВЫБРАТЬ КОГДА ТЕКУЩАЯДАТА() >= Акция.ДатаНачала

И ТЕКУЩАЯДАТА() <= Акция.ДатаОкончания

И Товар.Группа В (ВЫБРАТЬ Акция.ГруппыТоваров.Группа))

ГДЕ

Акция.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыАкций.Активна)

5.3. Связь сотрудников с графиками работы

Отчет по сотрудникам с указанием их графика на текущую дату:

ВЫБРАТЬ

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

График.Наименование КАК ГрафикРаботы,

График.НачалоРабочегоДня,

График.КонецРабочегоДня

ИЗ

Справочник.Сотрудники КАК Сотрудник

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикиРаботыСотрудников КАК График

ПО (ВЫБРАТЬ КОГДА ТЕКУЩАЯДАТА() >= График.Период

И ТЕКУЩАЯДАТА() < КОНЕЦДНЯ(График.Период)

И Сотрудник.Ссылка = График.Сотрудник)

Все поля в условии квалифицированы aliases'ами таблиц|Условие заключено в скобки (...)|Нет дублирования условий в ГДЕ и в соединении|Для дат используются функции начала/конца периода|Поля в условии проиндексированы в СУБД-->

6. Альтернативы ВЫБРАТЬ КОГДА: когда лучше использовать другие подходы

Условие ВЫБРАТЬ КОГДА не всегда оптимально. Рассмотрим альтернативы:

6.1. Виртуальные таблицы

Если нужно связать данные по сложному условию, иногда проще предварительно подготовить данные во временной таблице:

ВТ_Связи = НОВЫЙ ТаблицаЗначений;

ВТ_Связи.Колонки.Добавить("Документ");

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

// Заполняем связи заранее

ВЫБРАТЬ

Документ.Номер,

Регистр.Количество

ИЗ

Документ КАК Документ

ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Связи КАК Связи ПО Документ.Ссылка = Связи.Документ

ЛЕВОЕ СОЕДИНЕНИЕ Регистр КАК Регистр ПО Регистр.Ссылка = Связи.Регистр

6.2. Подзапросы в секции ГДЕ

Для простых условий иногда удобнее использовать В() или СУЩЕСТВУЕТ():

ВЫБРАТЬ

Документ.Номер

ИЗ

Документ КАК Документ

ГДЕ

СУЩЕСТВУЕТ(

ВЫБРАТЬ РАЗРЕШЕННЫЕ 1

ИЗ Регистр КАК Регистр

ГДЕ Регистр.Период = НАЧАЛОПЕРИОДА(Документ.Дата, Месяц)

)

6.3. Объединение нескольких простых запросов

Если условие связи слишком сложное, разбейте его на части с ОБЪЕДИНИТЬ:

ВЫБРАТЬ ... ПО (Условие1)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ ... ПО (Условие2)

💡

Если запрос с ВЫБРАТЬ КОГДА выполняется дольше 5 секунд, скорее всего, стоит рассмотреть альтернативные подходы. Начните с анализа плана выполнения в консоли 1С!

7. Особенности работы в разных версиях 1С

Поведение условия ВЫБРАТЬ КОГДА может отличаться в зависимости от версии платформы и СУБД:

Версия 1С / СУБД Особенности Рекомендации
1С 8.2, MS SQL Ограничение на сложность условий (не более 3-4 вложенных функций) Разбивайте сложные условия на подзапросы
1С 8.3.6+, PostgreSQL Поддержка оконных функций в условиях Можно использовать РАЗДЕЛИТЬ ПО() для аналитики
1С 8.3.10+, любая СУБД Оптимизатор лучше работает с виртуальными таблицами Предпочитайте временные таблицы для сложных связей
1С:ERP, Oracle Поддержка аналитических функций в условиях Используйте LAG()/LEAD() для сравнения с предыдущими записями

Для версий 1С ниже 8.3.8 условие ВЫБРАТЬ КОГДА с функциями дат (НАЧАЛОПЕРИОДА(), КОНЕЦПЕРИОДА()) может работать некорректно при переходе на летнее/зимнее время. В таких случаях используйте явное приведение к дате без времени:

ПО (ВЫБРАТЬ КОГДА НАЧАЛОДНЯ(Документ.Дата) >= НАЧАЛОДНЯ(Регистр.Период))
Как проверить, поддерживает ли ваша версия 1С сложные условия в ВЫБРАТЬ КОГДА?

Создайте тестовый запрос с условием, содержащим 5-6 вложенных функций (например, ЕСТЬNULL(НАЧАЛОПЕРИОДА(ДобавитьМесяц(Дата, 1), Квартал), Дата)). Если запрос компилируется без ошибок — ваша версия поддерживает сложные условия.

8. Практические советы по отладке

Отладка запросов с ВЫБРАТЬ КОГДА может быть сложной. Вот проверенные приемы:

8.1. Просмотр плана выполнения

В консоли запросов 1С (Отладка → План выполнения) обратите внимание на:

  • 🔍 Операции Nested Loops — признак неоптимального соединения.
  • 🔍 Table Scan — означает, что не используются индексы.
  • 🔍 Оценку количества строк (Estimated Rows) — если она сильно отличается от реальной, обновляйте статистику СУБД.

8.2. Поэтапное усложнение запроса

Начинайте с минимального рабочего примера, затем добавляйте условия:

// Шаг 1: только соединение без условий

ВЫБРАТЬ Д.Ссылка, Р.Ссылка

ИЗ Документ КАК Д ЛЕВОЕ СОЕДИНЕНИЕ Регистр КАК Р ПО 1=1

// Шаг 2: добавляем простое условие

ПО (ВЫБРАТЬ КОГДА Д.Дата = Р.Период)

// Шаг 3: усложняем условие

ПО (ВЫБРАТЬ КОГДА Д.Дата >= Р.Период И Д.Дата < КОНЕЦДНЯ(Р.Период))

8.3. Логирование промежуточных результатов

Для сложных запросов сохраняйте промежуточные данные во временные таблицы и проверяйте их содержимое:

ВТ_ПромежуточныйРезультат = НОВЫЙ ТаблицаЗначений;

// Заполняем через запрос с частью условий

ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_ПромежуточныйРезультат;

// Проверяем данные

Сообщить(ВТ_ПромежуточныйРезультат.Количество());

8.4. Использование конструктора запросов

В режиме 1С:Предприятие конструктор запросов визуализирует связи между таблицами, что помогает обнаружить ошибки в условиях.

💡

Если запрос с ВЫБРАТЬ КОГДА возвращает пустой результат, сначала проверьте, что обе таблицы содержат данные отдельными запросами. Часто проблема не в условии связи, а в фильтрах в секции ГДЕ.

⚠️ Внимание: В некоторых конфигурациях (например, 1С:ERP или 1С:УТ) стандартные регистры и документы имеют предопределенные индексы. Изменение структуры этих объектов может привести к поломке типовой функциональности. Перед добавлением новых индексов для оптимизации запросов сделайте резервную копию базы данных.

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

Можно ли использовать ВЫБРАТЬ КОГДА для соединения более двух таблиц?

Да, но с осторожностью. При соединении трех и более таблиц с условиями ВЫБРАТЬ КОГДА оптимизатор 1С может выбрать неэффективный план выполнения. В таких случаях:

  1. Сначала соединяйте таблицы с простыми условиями (=).
  2. Затем добавляйте таблицы с условием ВЫБРАТЬ КОГДА.
  3. Используйте временные таблицы для промежуточных результатов.

Пример:

ВЫБРАТЬ ...

ИЗ Таблица1 КАК Т1

ЛЕВОЕ СОЕДИНЕНИЕ Таблица2 КАК Т2 ПО Т1.Поле = Т2.Поле

ЛЕВОЕ СОЕДИНЕНИЕ Таблица3 КАК Т3

ПО (ВЫБРАТЬ КОГДА Т1.Дата >= Т3.Период И Т2.Статус = Т3.Статус)

Почему запрос с ВЫБРАТЬ КОГДА работает медленно, хотя данных мало?

Причины могут быть следующими:

  • 🐢 Отсутствуют индексы на поля, используемые в условии связи. Проверьте в конфигураторе (Все функции → Индексы).
  • 🐢 В условии используются функции, которые не могут использовать индексы (например, НАЙТИ(), СОКРЛП()).
  • 🐢 Сервер СУБД выбрал неоптимальный план. Попробуйте использовать подсказки оптимизатору (например, /+ INDEX(Таблица Индекс) / для Oracle).
  • 🐢 В временных таблицах не обновлена статистика. Выполните ОБНОВИТЬ СТАТИСТИКУ для базы данных.

Для диагностики:

  1. Посмотрите план выполнения запроса.
  2. Проверьте, какие индексы используются (или не используются).
  3. Упростите запрос, удаляя условия по одному, чтобы найти "узкое место".
Как связать таблицы по условию "последняя запись на дату"?

Это классическая задача для ВЫБРАТЬ КОГДА. Используйте конструкцию:

ВЫБРАТЬ

Документ.Номер,

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

ПоследняяЦ