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

Вы научитесь использовать операторы ГДЕ, И, ИЛИ, работать с параметрами, подзапросами и динамическими условиями. Особое внимание уделим типичным ошибкам, которые приводят к медленной работе запросов или некорректным результатам. Материал будет полезен как начинающим разработчикам, так и опытным программистам, которые хотят систематизировать знания.

Базовый синтаксис условия ГДЕ в 1С

Оператор ГДЕ (или WHERE в англоязычной нотации) — основа фильтрации данных в запросах . Он позволяет отбирать строки, соответствующие заданным критериям. Простейший пример:

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

Номенклатура.ПометкаУдаления = ЛОЖЬ

Здесь условие отбирает только не помеченные на удаление элементы справочника. Обратите внимание на ключевые моменты:

  • 🔹 Сравнение значений производится с помощью операторов =, <> (не равно), >, < и их комбинаций.
  • 🔹 Логические значения в 1С обозначаются как ИСТИНА/ЛОЖЬ, а не TRUE/FALSE.
  • 🔹 Регистрозависимость: названия полей и таблиц чувствительны к регистру (например, Наименованиенаименование).

Для проверки на пустое значение используйте конструкцию ЗНАЧЕНИЕ ЗАПОЛНЕНО():

ГДЕ

ЗНАЧЕНИЕ ЗАПОЛНЕНО(Документ.Контрагент)

💡

Если в условии нужно проверить несколько полей на заполненность, объединяйте их через И: ЗНАЧЕНИЕ ЗАПОЛНЕНО(Поле1) И ЗНАЧЕНИЕ ЗАПОЛНЕНО(Поле2).

Логические операторы И и ИЛИ: комбинирование условий

Для создания сложных фильтров используйте логические операторы:

  • 🔹 И — оба условия должны выполняться (логическое И).
  • 🔹 ИЛИ — достаточно выполнения хотя бы одного условия (логическое ИЛИ).
  • 🔹 НЕ — отрицание условия.

Пример с комбинацией операторов:

ГДЕ

(Документ.Дата >= &Параметры.ДатаНачала)

И (Документ.Дата <= &Параметры.ДатаОкончания)

И (Документ.Организация = &Параметры.Организация)

ИЛИ (Документ.СуммаДокумента > 100000)

⚠️ Внимание: Приоритет операторов в 1С отличается от математики! И имеет более высокий приоритет, чем ИЛИ. Используйте скобки для явного указания порядка выполнения.

Типичная ошибка — отсутствие скобок в условиях типа:

ГДЕ

Условие1 И Условие2 ИЛИ Условие3

В этом случае сначала вычисляется Условие1 И Условие2, а затем результат объединяется с Условие3 через ИЛИ. Если нужна другая логика, расставляйте скобки явным образом.

📊 Какой оператор вы используете чаще в условиях 1С?
И
ИЛИ
НЕ
Параметры

Работа с параметрами в условиях запроса

Параметры позволяют сделать запрос динамическим, передавая значения извне. В тексте запроса параметры обозначаются символом &:

ВЫБРАТЬ

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

Клиент.ИНН

ИЗ

Справочник.Контрагенты КАК Клиент

ГДЕ

Клиент.ВидКонтрагента = &ВидКонтрагента

И Клиент.ДатаРегистрации >= &ДатаРегистрации

Чтобы передать значение параметра из кода , используйте метод УстановитьПараметр():

Запрос.УстановитьПараметр("ВидКонтрагента", ВидКонтрагента.Покупатель);

Запрос.УстановитьПараметр("ДатаРегистрации", НачалоГода(ТекущаяДата()));

Преимущества использования параметров:

  • 🔹 Безопасность: защита от SQL-инъекций (1С автоматически экранирует значения).
  • 🔹 Производительность: план запроса кэшируется при повторном выполнении с теми же параметрами.
  • 🔹 Гибкость: один запрос можно использовать для разных сценариев.
⚠️ Внимание: Если параметр не установлен, 1С подставит значение НЕОПРЕДЕЛЕНО, что приведёт к ошибке при сравнении с полями, не поддерживающими NULL (например, числовыми). Всегда проверяйте передачу параметров!
Что будет, если не установить параметр?

Если параметр не установлен, при выполнении запроса возникнет ошибка "Параметр не найден" или "Некорректное значение параметра". В некоторых случаях (например, при сравнении со строковыми полями) 1С может подставить пустую строку, но это не гарантировано и зависит от контекста.

Специальные функции для условий: В(), МЕЖДУ, ПОДОБНО

Для упрощения записи условий в 1С предусмотрены специализированные функции:

Функция Описание Пример
В() Проверка вхождения в список значений ГДЕ Номенклатура.ВидНоменклатуры В (&Виды)
МЕЖДУ Проверка диапазона (включительно) ГДЕ Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
ПОДОБНО Поиск по шаблону (с поддержкой % и _) ГДЕ Наименование ПОДОБНО "Товар%"
НАЧИНАЕТСЯ Проверка начала строки ГДЕ Артикул НАЧИНАЕТСЯ "ART-"

Функция В() особенно полезна при работе со справочниками. Например, чтобы отобрать документы по нескольким организациям:

ГДЕ Документ.Организация В (&СписокОрганизаций)

Где &СписокОрганизаций — это массив или список значений, переданный как параметр. Важно: при использовании В() с большим количеством элементов (более 1000) производительность запроса может значительно упасть. В таких случаях лучше использовать временные таблицы.

Функция ПОДОБНО поддерживает шаблоны:

  • 🔹 % — любое количество символов (включая ноль).
  • 🔹 _ — ровно один символ.

Пример поиска артикулов, содержащих дефис:

ГДЕ Артикул ПОДОБНО "%-%"

Подзапросы и сложные условия

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

Пример: выбрать контрагентов, у которых есть неоплаченные счета:

ВЫБРАТЬ

Контрагент.Наименование

ИЗ

Справочник.Контрагенты КАК Контрагент

ГДЕ

EXISTS(

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

ИЗ Документ.СчетаНаОплату КАК Счет

ГДЕ Счет.Контрагент = Контрагент.Ссылка

И Счет.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыСчетов.Оплачен)

)

Ключевые моменты работы с подзапросами:

  • 🔹 Используйте EXISTS для проверки существования связанных записей.
  • 🔹 Для сравнения с агрегированными данными (например, суммой) используйте ВЫБРАТЬ ... В ().
  • 🔹 Подзапросы в условии ГДЕ должны возвращать одну колонку.

Пример с агрегатной функцией:

ГДЕ Документ.СуммаДокумента > (

ВЫБРАТЬ СУММА(СуммаДокумента) КАК СредняяСумма

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

)

⚠️ Внимание: Подзапросы в условиях ГДЕ могут существенно замедлить выполнение, если они коррелированы (ссылаются на поля внешнего запроса). В таких случаях рассмотрите возможность использования временных таблиц.

☑️ Оптимизация подзапросов

Выполнено: 0 / 4

Динамическое формирование условий

Иногда условия запроса зависят от пользовательских настроек или внешних данных. В таких случаях строку запроса можно формировать динамически.

Пример: добавление условия по организации, если она выбрана:

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

|ВЫБРАТЬ

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

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

|ИЗ

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

|";

Если ЗначениеЗаполнено(Организация) Тогда

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

|ГДЕ

| Документ.Организация = &Организация

";

КонецЕсли;

Для безопасного добавления параметров используйте метод ДобавитьПараметр():

Если ЗначениеЗаполнено(ДатаНачала) Тогда

Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ДатаНачала", "Документ.Дата >= &ДатаНачала");

Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);

КонецЕсли;

Альтернативный подход — использование конструкции ВЫРАЗИТЬ() для условной логики прямо в запросе:

ВЫБРАТЬ

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

ВЫРАЗИТЬ(ЕСТЬNULL(Документ.Комментарий, "") КАК СТРОКА(50)) КАК Комментарий

ИЗ

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

Преимущества динамического формирования:

  • 🔹 Гибкость: один запрос адаптируется под разные сценарии.
  • 🔹 Производительность: исключаются ненужные условия.

Недостатки:

  • 🔹 Сложность поддержки кода.
  • 🔹 Риск SQL-инъекций при некорректной обработке параметров.
💡

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

Оптимизация условий: индексы и планы выполнения

Неправильно составленные условия могут привести к полному сканированию таблиц (table scan), что критично для больших баз данных. Чтобы этого избежать, следуйте правилам:

  1. 🔢 Используйте индексированные поля в условиях. В 1С индексы автоматически создаются для полей с типом "Ссылка", "Дата", а также для полей, участвующих в соединениях.
  2. 🔢 Избегайте функций над полями в условиях. Например, вместо:
    ГДЕ ГОД(Документ.Дата) = 2023

    используйте:

    ГДЕ Документ.Дата МЕЖДУ '20230101' И '20231231'
  3. 🔢 Для текстовых полей используйте префиксный поиск (НАЧИНАЕТСЯ или ПОДОБНО "текст%"), а не СОДЕРЖИТ.

Чтобы проверить, как 1С выполняет запрос, используйте план выполнения:

Объяснить = Запрос.Выполнить().ВыгрузитьПланВременнойТаблицы();

Объяснить.Выгрузить();

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

  • 🔹 Полное сканирование (Seq Scan) вместо использования индекса.
  • 🔹 Большое количество операций Сортировка или Хэш-соединение.
  • 🔹 Высокая оценка стоимости (cost) в плане.
⚠️ Внимание: В последних версиях 1С (начиная с платформы 8.3.20) оптимизатор запросов стал "умнее", но всё равно требует контроля. Например, он может не использовать индекс, если статистика по таблице устарела. В таких случаях поможет вызов ОБНОВИТЬСТАТИСТИКУ().

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

Даже опытные разработчики допускают ошибки при составлении условий. Рассмотрим наиболее распространённые:

Ошибка Причина Как исправить
Сравнение разных типов Сравнение строки с числом или даты со строкой Явно приводите типы: ЧИСЛО(Поле) = 100
Неучтённые NULL Поля могут содержать NULL, что ломает логику Используйте ЗНАЧЕНИЕ ЗАПОЛНЕНО() или ЕСТЬNULL()
Избыточные условия Условия, которые всегда истинны или ложны Упрощайте логику, убирайте лишние проверки
Неправильный приоритет операторов И выполняется раньше ИЛИ Используйте скобки для явного указания приоритета

Пример ошибки с типами:

ГДЕ Документ.Номер = "000123"  // Сравнивается строка с числом!

Правильный вариант:

ГДЕ Документ.Номер = ЧИСЛО("000123")  // Или СТРОКА(Документ.Номер) = "000123"

Ещё одна частая проблема — игнорирование регистра при сравнении строк:

ГДЕ Наименование = "товар"  // Не найдёт "Товар" или "ТОВАР"

Решение:

ГДЕ ВРЕГ(Наименование) = ВРЕГ("товар")

Для проверки на NULL никогда не используйте конструкцию = NULL. Вместо этого:

ГДЕ Документ.Поле ЕСТЬ NULL  // Правильно

ГДЕ Документ.Поле = NULL // Ошибка!

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

Как в условии запроса проверить, что поле содержит одно из нескольких значений?

Используйте оператор В():

ГДЕ Номенклатура.ВидНоменклатуры В (&МассивВидов)

где &МассивВидов — это массив или список значений, переданный как параметр. Например:

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

МассивВидов.Добавить(ВидНоменклатуры.Товар);

МассивВидов.Добавить(ВидНоменклатуры.Услуга);

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

Можно ли в условии запроса использовать свои функции?

Нет, в тексте запроса можно использовать только встроенные функции 1С (например, НАЧИНАЕТСЯ(), ЗНАЧЕНИЕЗАПОЛНЕНО()). Для использования своих функций придётся:

  1. Выгрузить данные во временную таблицу.
  2. Обработать их в коде с помощью своей функции.
  3. При необходимости вернуть результат в новый запрос.

Исключение — функции, зарегистрированные как расширяющие язык запросов (доступно в последних версиях платформы).

Как оптимизировать запрос с большим количеством условий?

Следуйте этим рекомендациям:

  • 🔹 Перенесите статичные условия (например, по организации) в начало запроса.
  • 🔹 Разбейте сложный запрос на несколько простых с использованием временных таблиц.
  • 🔹 Замените подзапросы в ГДЕ на соединения (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ).
  • 🔹 Используйте ИНДЕКСИРОВАТЬ ПО для указания полей, по которым должен строиться индекс.

Пример оптимизированного запроса:

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

Документ.Организация = &Организация

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

ИНДЕКСИРОВАТЬ ПО

Организация,

Дата

Почему запрос игнорирует моё условие по дате?

Частые причины:

  1. Неверный формат даты: Убедитесь, что передаёте дату как Дата, а не строку. Например:
    Запрос.УстановитьПараметр("ДатаНачала", '20230101');  // Ошибка!
    

    Запрос.УстановитьПараметр("ДатаНачала", Дата(2023, 1, 1)); // Правильно

  2. Проблемы с временной зоной: Если в базе хранятся даты с временем, а вы сравниваете только с датой, используйте:
    ГДЕ НачалоПериода(Документ.Дата, ДЕНЬ) = &ДатаНачала
  3. Неучтённое время: Для диапазона дат всегда используйте:
    ГДЕ Документ.Дата >= НачалоДня(&ДатаНачала)
    

    И Документ.Дата < КонецДня(&ДатаОкончания)

Как задать условие по связанному справочнику?

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

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

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

Если связь многоуровневая (например, номенклатура → вид номенклатуры → категория), используйте цепочку:

ГДЕ Документ.Номенклатура.ВидНоменклатуры.Категория = &Категория
⚠️ Внимание: Фильтрация по связанным справочникам может быть медленной, если поля не проиндексированы. В таких случаях рассмотрите денормализацию данных или использование регистров сведений.