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

В этой статье мы разберём не только базовый синтаксис условия ГДЕ, но и нюансы работы с логическими операторами (И, ИЛИ, НЕ), специальными функциями вроде В() или ПОДОБНО(), а также типичные ошибки, которые приводят к пустым выборкам или зависанию запросов. Особое внимание уделим оптимизации — как правильно строить условия, чтобы они выполнялись быстро даже на больших объёмах данных.

Если вы только начинаете осваивать язык запросов , начните с первых разделов. Для опытных программистов будут полезны разделы про неявные преобразования типов в условиях и особенности работы с виртуальными таблицами — эти моменты редко освещаются в документации, но критичны для стабильной работы систем.

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

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

ВЫБРАТЬ

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

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

ИЗ

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

ГДЕ

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

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

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

Если условие не указано вовсе, запрос вернёт все записи из источника. Но в реальных задачах это встречается редко — обычно требуется хоть минимальная фильтрация.

📊 Как часто вы используете условие ГДЕ в запросах 1С?
В каждом запросе
Только для сложных отборов
Редеко, предпочитаю обработку в коде
Не использую, работаю с объектами напрямую

2. Логические операторы: И, ИЛИ, НЕ

Для построения сложных условий в используются логические операторы, которые позволяют комбинировать несколько критериев. Рассмотрим их на примерах:

Оператор Описание Пример
И (AND) Оба условия должны выполняться ГДЕ Дата >= &НачалоПериода И Дата <= &КонецПериода
ИЛИ (OR) Хотя бы одно условие должно выполняться ГДЕ ВидДокумента = &Вид1 ИЛИ ВидДокумента = &Вид2
НЕ (NOT) Отрицание условия ГДЕ НЕ ПометкаУдаления (эквивалентно = ЛОЖЬ)

Важный нюанс: порядок вычисления условий определяется приоритетом операторов. Так, И имеет более высокий приоритет, чем ИЛИ. Например, в запросе:

ГДЕ

ВидДокумента = &Вид1 ИЛИ ВидДокумента = &Вид2 И Дата > &НачалоПериода

условие Дата > &НачалоПериода относится только ко второму виду документа. Чтобы применить его ко всем видам, нужно использовать скобки:

ГДЕ

(ВидДокумента = &Вид1 ИЛИ ВидДокумента = &Вид2)

И Дата > &НачалоПериода

💡

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

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

Помимо стандартных сравнений (=, >, <), в есть специализированные функции для фильтрации:

  • 📋 В() — проверка вхождения значения в список. Пример:
    ГДЕ Склад В (&СписокСкладов)

    Здесь &СписокСкладов — массив или запятая через запятую: В("Склад1", "Склад2").

  • 🔍 ПОДОБНО() — поиск по шаблону с поддержкой подстановочных символов % (любая последовательность) и _ (один символ). Пример:
    ГДЕ Наименование ПОДОБНО "Товар% "

    Найдёт все наименования, начинающиеся на "Товар".

  • 📅 МЕЖДУ — проверка попадания значения в диапазон. Пример:
    ГДЕ Дата МЕЖДУ &Начало И &Конец

    Эквивалентно Дата >= &Начало И Дата <= &Конец, но короче и читаемее.

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

ГДЕ ВидДокумента В (&ВидыДокументов)

где &ВидыДокументов — параметр запроса типа Массив. Это избавляет от необходимости писать длинные цепочки ИЛИ.

Чем отличается В() от множества ИЛИ?

Функция В() оптимизирована платформой 1С и обычно выполняется быстрее, чем эквивалентная конструкция с ИЛИ, особенно при большом количестве значений. Кроме того, код с В() лаконичнее и легче поддерживается.

4. Работа с датами и временными интервалами

Фильтрация по датам — одна из самых частых задач в . Здесь есть несколько нюансов, о которых многие забывают:

⚠️ Внимание: При сравнении дат без указания времени (ДатаДокумента = &ТекущаяДата) платформа автоматически добавляет время 00:00:00. Это означает, что документы, проведённые в течение дня, не попадут в выборку! Всегда используйте диапазоны:
ГДЕ

ДатаДокумента >= НачалоДня(&ТекущаяДата)

И ДатаДокумента < КонецДня(&ТекущаяДата)

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

  • 🕒 НачалоДня(), КонецДня() — обрезают время до 00:00:00 и 23:59:59 соответственно.
  • 📆 ДобавитьМесяц(), ДобавитьДень() — сдвигают дату на заданный период. Пример:
    ГДЕ Дата >= ДобавитьМесяц(ТекущаяДата(), -1)

    Вернёт записи за последний месяц.

  • ТЕКУЩАЯДАТА() — возвращает текущую дату сервера (учитывает настройки временной зоны).

Если нужно отфильтровать данные по кварталам или годам, лучше использовать виртуальные таблицы (например, Документ.РеализацияТоваровУслуг.ПоМесяцам), так как они оптимизированы для таких запросов.

5. Условия для ссылочных полей и пустых значений

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

  1. Сравнение по ссылке — если поле содержит ссылку на объект, его можно сравнивать напрямую:
    ГДЕ Контрагент = &ВыбранныйКонтрагент

    Здесь &ВыбранныйКонтрагент должен быть ссылкой на элемент справочника Контрагенты.

  2. Проверка на заполненность — для проверки, что поле не пустое, используйте ЗНАЧЕНИЕЗАПОЛНЕНО():
    ГДЕ ЗНАЧЕНИЕЗАПОЛНЕНО(Контрагент)

    Это корректнее, чем Контрагент <> NULL, так как учитывает особенности хранения ссылок в .

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

ГДЕ Номенклатура.Родитель = &ВыбраннаяГруппа

Но такой запрос не вернёт номенклатуру из вложенных групп! Чтобы получить все элементы группы и её подгрупп, используйте рекурсивный обход или виртуальную таблицу ПолнаяИерархия:

ВЫБРАТЬ

НоменклатураПолнаяИерархия.Ссылка КАК Номенклатура

ИЗ

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

ГДЕ

НоменклатураПолнаяИерархия.Родитель = &ВыбраннаяГруппа

💡

Для проверки ссылочных полей на пустоту всегда используйте ЗНАЧЕНИЕЗАПОЛНЕНО() — это гарантирует корректную работу с любыми типами ссылок, включая пустые и удалённые объекты.

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

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

  • 🚀 Индексируемые поля — условия по полям, которые входят в индексы таблиц, выполняются быстрее. В индексы автоматически создаются для:
    • Ключевых полей (например, Ссылка в справочниках).
    • Полей, помеченных как индексируемые в конфигураторе.
    • Полей, участвующих в связях между таблицами.
  • 🔍 Избегайте функций в условиях — если в условии используется функция (например, НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ)), индексы не применяются. Лучше вынести вычисление в параметр:
    ГДЕ Дата >= &НачалоМесяца
  • 📊 Ограничивайте объём данных — если нужно получить только последние записи, добавьте условие по дате или идентификатору:
    ГДЕ Дата >= ДобавитьМесяц(ТЕКУЩАЯДАТА(), -3)

    Это сократит объём сканируемых данных.

Для анализа производительности используйте план выполнения запроса (доступен в конфигураторе через меню Отладка → Показать план запроса). Он покажет, какие части запроса наиболее ресурсоёмкие.

⚠️ Внимание: Условия с оператором ПОДОБНО() по полям без индексов могут приводить к полному сканированию таблицы (Table Scan). Если такой запрос выполняется долго, рассмотрите возможность создания индекса или перепишите условие с использованием ВРЕГ() и точного сравнения.

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

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

Ошибка Причина Как исправить
Пустая выборка при корректных данных Несовпадение типов (например, сравнение числа со строкой). Явно преобразуйте типы: ГДЕ ЧИСЛО(Код) = 123.
Запрос "висит" без результата Слишком сложное условие без индексов или рекурсивный обход больших иерархий. Разбейте запрос на части или используйте временные таблицы.
Некорректная фильтрация по датам Игнорирование времени (см. раздел 4). Всегда используйте НачалоДня()/КонецДня().
Ошибка "Поле не найдено" Опечатка в имени поля или псевдониме таблицы. Проверьте регистр и псевдонимы (например, КАК Ном → обращение Ном.Поле).

Ещё одна распространённая проблема — неявные преобразования типов. Например, если поле Код имеет тип Строка, а вы сравниваете его с числом:

ГДЕ Код = 123

платформа попытается автоматически преобразовать строку в число. Это может приводить к ошибкам, если строка содержит недопустимые символы. Всегда явно указывайте тип:

ГДЕ Код = "123"  // если поле строковое

ИЛИ

ГДЕ ЧИСЛО(Код) = 123

8. Практический пример: сложный запрос с несколькими условиями

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

ВЫБРАТЬ

Реализация.Номер КАК НомерДокумента,

Реализация.Дата,

Реализация.Контрагент,

РеализацияТовары.Номенклатура,

РеализацияТовары.Количество,

РеализацияТовары.Сумма

ИЗ

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары

ПО Реализация.Ссылка = РеализацияТовары.Ссылка

ГДЕ

Реализация.Дата МЕЖДУ НачалоМесяца(ТЕКУЩАЯДАТА()) И КонецМесяца(ТЕКУЩАЯДАТА())

И Реализация.Контрагент В (&СписокКонтрагентов)

И НЕ Реализация.ПометкаУдаления

И НЕ Реализация.Проведен = ЛОЖЬ // исключаем непроводённые документы

И РеализацияТовары.Количество > 10

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

Реализация.Дата УБЫВ

Обратите внимание на:

  • 🔗 Использование ВНУТРЕННЕЕ СОЕДИНЕНИЕ для связи таблицы документа и его табличной части.
  • 📅 Корректную фильтрацию по датам с учётом начала и конца месяца.
  • 🚫 Исключение удалённых и непроводённых документов.
  • 📦 Дополнительный фильтр по количеству в табличной части.

Указаны все необходимые поля в SELECT|Правильно расставлены скобки в условиях|Поля в ГДЕ соответствуют полям в источниках|Для дат использованы НачалоДня()/КонецДня()|Проверены типы данных в сравнениях-->

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

Можно ли в условии ГДЕ использовать подзапрос?

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

ГДЕ Контрагент В (

ВЫБРАТЬ РАЗЛИЧНЫЕ Контрагент

ИЗ Документ.ЗаказыПокупателей

ГДЕ Дата >= &НачалоПериода

)

Для больших баз такой подзапрос может быть неэффективен.

Почему условие с ПОДОБНО() не находит нужные строки?

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

  1. Не учтён регистр символов (по умолчанию поиск регистрозависимый). Используйте ВРЕГ() для приведения к верхнему регистру:
    ГДЕ ВРЕГ(Наименование) ПОДОБНО ВРЕГ("товар%")
  2. В шаблоне пропущены пробелы. Символ % заменяет любые символы, включая пробелы. Если ищете "Товар 1", шаблон должен быть "Товар%", а не "Товар %".
  3. Поле содержит непечатаемые символы (например, табуляцию). Проверьте данные через СТРЗАМЕНИТЬ().
Как отфильтровать данные по нескольким значениям из массива?

Используйте функцию В() с параметром типа Массив:

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

Где &МассивНоменклатуры — параметр запроса, содержащий массив ссылок на номенклатуру. Альтернатива — передача списка через запятую:

ГДЕ Номенклатура В (ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура ИЗ &ВременнаяТаблица)

Для больших массивов (сотни значений) второй вариант предпочтительнее.

Что делать, если условие с датой возвращает неверные данные?

Проверьте:

  • Учтено ли время? Например, Дата = &ТекущаяДата не найдёт документы, созданные после 00:00:00. Используйте диапазон:
  • ГДЕ Дата >= НачалоДня(&ТекущаяДата)
    

    И Дата < КонецДня(&ТекущаяДата)

  • Верная ли временная зона? Функция ТЕКУЩАЯДАТА() возвращает дату сервера , которая может отличаться от локальной даты клиента.
  • Нет ли неявного приведения типов? Например, если поле Дата имеет тип Строка, сравнение с датой работать не будет.
Можно ли в условии ГДЕ использовать свои функции?

Технически да, но это крайне не рекомендуется. Пользовательские функции в условиях:

  • 🚫 Не используют индексы — запрос будет сканировать все строки.
  • 🐢 Замедляют выполнение, так как вычисляются для каждой записи.
  • 🔄 Могут приводить к неожиданным результатам из-за контекста выполнения.

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

ГДЕ МояФункция(Поле) = ИСТИНА

лучше сделать:

ВЫБРАТЬ ...

ГДЕ Поле В (

ВЫБРАТЬ Значение

ИЗ &ВременнаяТаблицаСРезультатамиФункции

)