Как отбирать записи в языке запросов 1С: всё про секцию ГДЕ

· 10 мин

Содержание

Условие ГДЕ в запросе 1С отбирает строки до группировки: пишется после ИЗ и всех соединений, но перед СГРУППИРОВАТЬ ПО. Простейший пример — ГДЕ Документ.Проведен И Документ.Дата МЕЖДУ &НачалоПериода И &КонецПериода. Всё, что сравнивается со значениями извне, передавайте параметрами через &, а не склеивайте в текст запроса.

Синтаксис одинаков для всей платформы 8.3 и не зависит от конфигурации: в Бухгалтерии, ЗУП и УТ условия пишутся одними и теми же операторами. Разница только в именах таблиц и реквизитов.

Где стоит ГДЕ в тексте запроса и как записать условие

Порядок секций в запросе жёсткий. Перепутаете — получите синтаксическую ошибку при выполнении.

ВЫБРАТЬ
    Реализация.Ссылка,
    Реализация.Контрагент,
    Реализация.СуммаДокумента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Проведен
    И Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И Реализация.СуммаДокумента > 100000
УПОРЯДОЧИТЬ ПО
    Реализация.Дата

Полный порядок такой: ВЫБРАТЬ → ПОМЕСТИТЬ → ИЗ → соединения → ГДЕ → СГРУППИРОВАТЬ ПО → ИМЕЮЩИЕ → УПОРЯДОЧИТЬ ПО → ИТОГИ.

Что нужно знать о самом условии:

  • 🔹 Логическое поле можно писать без сравнения: ГДЕ Реализация.Проведен равносильно = ИСТИНА, а ГДЕ НЕ Реализация.ПометкаУдаления — отбор неудалённых.
  • 🔹 Условия соединяются через И, ИЛИ, НЕ. Приоритет: сначала НЕ, потом И, потом ИЛИ. Смешиваете И с ИЛИ — ставьте скобки.
  • 🔹 Псевдоним поля из ВЫБРАТЬ в ГДЕ использовать нельзя. Повторите выражение целиком.
  • 🔹 Агрегатные функции (СУММА, КОЛИЧЕСТВО) в ГДЕ недопустимы — для отбора по итогам есть ИМЕЮЩИЕ.

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

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Контрагент);
КонецЦикла;

В конструкторе запроса условия собираются на вкладке «Условия». Перетащите поле в правую часть — конструктор сам предложит параметр. Для выражения сложнее простого сравнения поставьте флажок «Произвольное» и напишите условие текстом.

ГДЕ или ИМЕЮЩИЕ

Что отбираемСекцияПример
Строки исходной таблицыГДЕГДЕ Продажи.Склад = &Склад
Группы по итогуИМЕЮЩИЕИМЕЮЩИЕ СУММА(Продажи.Сумма) > 50000
И то и другоеобесначала ГДЕ, затем ИМЕЮЩИЕ

Чем больше строк отсечёт ГДЕ, тем меньше работы у группировки. Поэтому условие на исходные поля в ИМЕЮЩИЕ не переносите.

Операторы условия ГДЕ: сравнение, списки, иерархия, типы

Базовое сравнение — =, <>, <, >, <=, >=. Остальные операторы закрывают типовые задачи отбора.

ОператорЧто делаетПример
МЕЖДУ … И …Диапазон, обе границы включаютсяДата МЕЖДУ &Начало И &Конец
В (…)Значение входит в списокСклад В (&СписокСкладов)
В ИЕРАРХИИ (…)Элемент или любой потомок группыНоменклатура В ИЕРАРХИИ (&Группа)
ПОДОБНООтбор по шаблону строкиНаименование ПОДОБНО "%болт%"
ЕСТЬ NULLЗначение отсутствуетОстатки.Количество ЕСТЬ NULL
ССЫЛКАСсылка нужного типа в составном полеРегистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Списки значений

В параметр для оператора В передают массив или список значений. Для пары-тройки фиксированных значений подойдёт и литерал:

ГДЕ
    Контрагенты.ЮридическоеФизическоеЛицо В (
        ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ЮридическоеЛицо),
        ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ФизическоеЛицо))

Функция ЗНАЧЕНИЕ() позволяет вписать предопределённое значение, значение перечисления или пустую ссылку прямо в текст запроса без параметра.

💡 Отрицание пишется как НЕ Склад В (&Склады). Если список пустой, В не отберёт ничего, а НЕ … В отберёт всё. Проверяйте пустоту списка в коде до запуска, иначе отчёт молча покажет либо ноль, либо всю базу.

Отбор по типу составного поля

У регистраторов, субконто и реквизитов составного типа удобно ограничивать тип значения:

ГДЕ
    Движения.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
    ИЛИ Движения.Регистратор ССЫЛКА Документ.ВозвратТоваровОтКлиента

Альтернатива — ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.ПоступлениеТоваровУслуг). Результат тот же, ССЫЛКА короче. Имена документов в примерах взяты из типовых конфигураций — в вашей базе сверяйте их по дереву метаданных или через конструктор.

Даты и строки в условиях запроса

Отбор по датам

Главная ловушка — время в дате. Документ от 31 марта 15:40 не попадёт в отбор Дата <= &Конец, если в параметр передали 31 марта 00:00:00. Решений два:

  1. Передавать конец периода через КонецДня() в коде, как в примере выше.
  2. Округлять внутри запроса: МЕЖДУ НАЧАЛОПЕРИОДА(&Начало, ДЕНЬ) И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ).

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

  • 📅 ДАТАВРЕМЯ(2025, 1, 1) — дата-литерал; ДАТАВРЕМЯ(1, 1, 1) — пустая дата.
  • 📅 НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и КОНЕЦПЕРИОДА(Дата, КВАРТАЛ) — границы периода.
  • 📅 ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -30) — сдвиг даты.
  • 📅 РАЗНОСТЬДАТ(Документ.Дата, &ТекущаяДата, ДЕНЬ) — разница в днях.

Пример: счета старше 30 дней от даты отчёта.

ГДЕ
    РАЗНОСТЬДАТ(Счет.Дата, &ДатаОтчета, ДЕНЬ) > 30

Этот вариант читается легко, но индекс по дате он не использует. На больших таблицах лучше Счет.Дата < ДОБАВИТЬКДАТЕ(&ДатаОтчета, ДЕНЬ, -30) — функция применяется к параметру, а поле остаётся «чистым».

Отбор по строкам: ПОДОБНО

ПОДОБНО сравнивает строку с шаблоном. Спецсимволы шаблона:

СимволЗначение
%Любое количество любых символов, в том числе ноль
_Ровно один любой символ
[абв]Один символ из перечисленных
[а-я]Один символ из диапазона
[^0-9]Один символ, не входящий в диапазон

Поиск подстроки, введённой пользователем:

ГДЕ
    Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~"

В коде шаблон собирают так: "%" + СтрЗаменить(Строка, "%", "~%") + "%". Если пользователь ввёл 50%, без экранирования знак процента сработает как шаблон и отбор станет шире. По-хорошему экранируют и _, и квадратные скобки.

⚠️ Строки неограниченной длины (реквизиты вроде «Комментарий» с длиной 0) напрямую сравнивать через = нельзя — запрос упадёт. Приведите поле к строке фиксированной длины: ВЫРАЗИТЬ(Документ.Комментарий КАК СТРОКА(200)) = &Текст.

NULL, пустые ссылки и пустые значения

В 1С это три разные вещи, и путают их постоянно.

  • ⚪ NULL — значения нет вообще. Появляется в левом соединении, когда справа не нашлось пары, и в составных полях, если реквизит не относится к данному типу.
  • ⚪ Пустая ссылка — значение есть, но ссылка ни на что не указывает. Например, документ без заполненного контрагента.
  • ⚪ НЕОПРЕДЕЛЕНО — пустое значение в реквизите составного типа, пока тип не выбран.

Как проверять:

// Значения нет совсем
ГДЕ Остатки.КоличествоОстаток ЕСТЬ NULL

// Контрагент не заполнен
ГДЕ Реализация.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)

// Пустая дата
ГДЕ Документ.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)

Сравнение Поле = NULL никогда не даёт истину — даже если в поле действительно NULL. Только ЕСТЬ NULL и ЕСТЬ НЕ NULL.

Для составного поля «не заполнено» означает сразу несколько состояний. Надёжная проверка:

ГДЕ
    (Движения.Субконто1 ЕСТЬ NULL
        ИЛИ Движения.Субконто1 = НЕОПРЕДЕЛЕНО)

Если нужно отобрать пустые ссылки конкретного типа — добавьте сравнение с ЗНАЧЕНИЕ(…ПустаяСсылка) этого типа.

💡 Когда NULL мешает в арифметике, используйте ЕСТЬNULL(Поле, 0). Выражение ЕСТЬNULL(Остатки.КоличествоОстаток, 0) = 0 отберёт и товары с нулевым остатком, и товары, у которых записей в регистре нет совсем.

Подзапросы, соединения и виртуальные таблицы в условии

Вложенный запрос в операторе В

Оператора СУЩЕСТВУЕТ в языке запросов 1С нет. Его роль выполняет В с вложенным запросом:

ВЫБРАТЬ
    Контрагенты.Ссылка
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    Контрагенты.Ссылка В (
        ВЫБРАТЬ
            Реализация.Контрагент
        ИЗ
            Документ.РеализацияТоваровУслуг КАК Реализация
        ГДЕ
            Реализация.Проведен
            И Реализация.Дата >= &НачалоГода)

Сравнивать можно и несколько полей сразу: (Т.Номенклатура, Т.Склад) В (ВЫБРАТЬ … ). Вложенный запрос должен вернуть столько же полей, в том же порядке.

Левое соединение, которое превращается во внутреннее

Классическая ошибка: условие на правую таблицу левого соединения поставили в ГДЕ.

ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК Цены
    ПО Номенклатура.Ссылка = Цены.Номенклатура
ГДЕ
    Цены.ВидЦены = &ВидЦены

Для товаров без цены поле Цены.ВидЦены равно NULL, условие ложно, и эти товары пропадают. Смысл левого соединения потерян. Правильно — перенести условие в ПО или, ещё лучше, в параметры виртуальной таблицы:

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ВидЦены) КАК Цены
ПО Номенклатура.Ссылка = Цены.Номенклатура

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

Условие в параметрах виртуальной таблицы и в ГДЕ — не одно и то же

У виртуальных таблиц регистров есть параметр «Условие»:

ТаблицаПараметры
ОстаткиПериод, Условие
ОборотыНачало, Конец, Периодичность, Условие
СрезПоследнихПериод, Условие

Условие в параметрах применяется до расчёта таблицы, а ГДЕ — к уже готовому результату. Для остатков по измерениям итог совпадает, но параметр работает быстрее: платформа не считает лишнего.

Для СрезПоследних разница бывает смысловой. Условие по ресурсу или реквизиту в параметрах даст «последнюю запись среди подходящих», а в ГДЕ — «последнюю запись, если она подходит». Запись, которая была последней месяц назад, во втором случае не найдётся.

Как ускорить отбор: оптимизация условий ГДЕ

Медленный запрос почти всегда медленный из-за условий. Что проверить в первую очередь:

  1. Функция над полем. ГДЕ ГОД(Документ.Дата) = 2025 заставляет СУБД вычислить год для каждой строки. Замена — Документ.Дата МЕЖДУ ДАТАВРЕМЯ(2025, 1, 1) И ДАТАВРЕМЯ(2025, 12, 31, 23, 59, 59).
  2. ИЛИ по разным полям. ГДЕ Т.Поставщик = &К ИЛИ Т.Покупатель = &К часто не использует индексы. Разбейте на два запроса и объедините через ОБЪЕДИНИТЬ ВСЕ (или ОБЪЕДИНИТЬ, если возможны дубли).
  3. Разыменование через точку. ГДЕ Реализация.Контрагент.ИНН = &ИНН добавляет неявное соединение. Для составного поля вроде Регистратор.Склад соединений будет столько, сколько типов в составе. Сужайте тип через ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Склад, а отбор по ИНН делайте в подзапросе или временной таблице.
  4. Отбор по виртуальной таблице в ГДЕ. Переносите условие в параметры таблицы, как описано выше.
  5. Длинный список в В. Сотни и тысячи значений лучше положить во временную таблицу через ПОМЕСТИТЬ и соединиться с ней, чем передавать огромный массив.
  6. Неиндексируемый реквизит. Если постоянно отбираете по реквизиту справочника или документа, проверьте у него в конфигураторе свойство «Индексировать». Менять его в типовой конфигурации — доработка, согласуйте с тем, кто сопровождает базу.

💡 Посмотреть, во что превратился запрос на уровне СУБД, помогает технологический журнал или замер производительности в режиме отладки. Сравнивайте время до и после правки на одной и той же выборке, а не на глаз.

Ошибки в условиях ГДЕ и как их распознать

Диагностика: выберите симптом

Готовые примеры условий для частых задач

Неоплаченные заказы конкретного менеджера за квартал

ГДЕ
    Заказ.Проведен
    И Заказ.Ответственный = &Менеджер
    И Заказ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, КВАРТАЛ) И КОНЕЦПЕРИОДА(&Дата, КВАРТАЛ)

Условие по оплате зависит от того, как в конфигурации хранится состояние заказа: где-то это реквизит, где-то регистр расчётов. Его добавляйте по своей базе.

Товары группы с отрицательным остатком

ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(
        &Дата,
        Номенклатура В ИЕРАРХИИ (&Группа)) КАК Остатки
ГДЕ
    Остатки.КоличествоОстаток < 0

Отбор по группе стоит в параметре таблицы, а условие на ресурс — в ГДЕ: ресурс остатка до расчёта неизвестен.

Контрагенты без ИНН, не помеченные на удаление

ГДЕ
    НЕ Контрагенты.ЭтоГруппа
    И НЕ Контрагенты.ПометкаУдаления
    И Контрагенты.ИНН = ""

Движения только от нужных документов

ГДЕ
    Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
    И Движения.Период МЕЖДУ &Начало И &Конец

Необязательный отбор, который включается из формы

ГДЕ
    (&ОтборПоСкладу = ЛОЖЬ ИЛИ Продажи.Склад = &Склад)

Если флажок в форме снят, первое условие истинно и отбор по складу не работает. Это удобно, но на больших таблицах такое ИЛИ с параметром может мешать индексу. Альтернатива — дописывать строку условия в текст запроса в коде только тогда, когда отбор нужен.

Частые вопросы

Регистр букв в ключевых словах запроса важен?
Нет. ГДЕ, где и WHERE равнозначны: язык запросов принимает и русский, и английский синтаксис, регистр ключевых слов не учитывается.
Можно ли в ГДЕ сравнить поле с другим полем той же таблицы?
Да. Например, ГДЕ Документ.СуммаОплаты < Документ.СуммаДокумента — обычное условие, параметры не нужны.
Чем ЕСТЬNULL отличается от ЕСТЬ NULL?
ЕСТЬ NULL — проверка, возвращает истину или ложь. ЕСТЬNULL(Поле, Значение) — функция, подставляет замену вместо NULL и используется в выражениях.
Как передать в запрос пустой отбор, чтобы он не ограничивал выборку?
Через дополнительный логический параметр: (&Использовать = ЛОЖЬ ИЛИ Поле = &Значение). Либо собирайте текст условия в коде только при заполненном отборе.
Почему отбор по табличной части возвращает один документ несколько раз?
Каждая подходящая строка табличной части даёт отдельную запись результата. Если нужны только документы, где хотя бы одна строка подходит, отбирайте Ссылка В (ВЫБРАТЬ Ссылка ИЗ Документ.Имя.Товары ГДЕ …).