Отбор данных в языке запросов 1С 8.3: какие условия бывают и где их писать
Содержание
Условие в запросе 1С ставят в секции ГДЕ после ИЗ: ГДЕ Документ.Проведен = ИСТИНА И Документ.Дата МЕЖДУ &Начало И &Конец. Значения из кода передают параметрами через Запрос.УстановитьПараметр("Начало", НачалоДня(ДатаНачала)), а не вклеивают в текст. В конструкторе запроса то же самое делается на вкладке «Условия».
Типичная ситуация: отчёт по реализации показывает все документы подряд, включая непроведённые и помеченные на удаление. Нужно отсечь лишнее, оставить один период и одного контрагента. Ниже — синтаксис условий языка запросов 1С 8.3 с примерами, от простого фильтра до подзапросов. Язык запросов общий для платформы, поэтому всё работает в любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11 и своих разработках. Имена объектов в примерах взяты из Бухгалтерии предприятия.
Секция ГДЕ и операторы сравнения
Минимальный запрос с условием выглядит так:
ВЫБРАТЬ
Реализация.Ссылка,
Реализация.Дата,
Реализация.СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
И НЕ Реализация.ПометкаУдаления
И Реализация.СуммаДокумента > 10000
Булево поле можно писать без = ИСТИНА: ГДЕ Реализация.Проведен читается так же. Секция ГДЕ стоит после ИЗ и соединений, но перед СГРУППИРОВАТЬ ПО и УПОРЯДОЧИТЬ ПО.
Какие операторы доступны:
| Оператор | Что проверяет | Пример |
|---|---|---|
=, <> | равно / не равно | Склад = &Склад |
>, <, >=, <= | больше / меньше | Количество >= 5 |
МЕЖДУ … И … | диапазон включительно | Дата МЕЖДУ &Начало И &Конец |
В (…) | значение из списка | Склад В (&Склады) |
В ИЕРАРХИИ (…) | элемент или любой его потомок | Номенклатура В ИЕРАРХИИ (&Группа) |
ПОДОБНО | строка по шаблону | Наименование ПОДОБНО "%кабель%" |
ЕСТЬ NULL | поле не заполнено соединением | Остатки.Количество ЕСТЬ NULL |
ССЫЛКА | тип ссылки в составном поле | Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг |
Шаблоны для ПОДОБНО
- 🔹
%— любое количество любых символов, в том числе ноль; - 🔹
_— ровно один любой символ; - 🔹
[а-в]— один символ из диапазона,[^0-9]— любой, кроме цифры.
Если сам символ % или _ нужно искать буквально, добавьте СПЕЦСИМВОЛ: Артикул ПОДОБНО "%!_%" СПЕЦСИМВОЛ "!" найдёт артикулы с подчёркиванием.
Шаблон для ПОДОБНО тоже удобно передавать параметром. Склейте его в коде: Запрос.УстановитьПараметр("Шаблон", "%" + СтрокаПоиска + "%"), а в тексте оставьте ПОДОБНО &Шаблон.
Условие через конструктор запроса
Если текст писать не хочется, откройте конструктор (в модуле — правой кнопкой по тексту запроса или через меню Текст → Конструктор запроса). Порядок такой:
- На вкладке «Таблицы и поля» выберите таблицу и поля.
- Перейдите на вкладку «Условия».
- Перетащите поле из левого списка в правый — конструктор сам подставит условие вида
Поле = &Полеи создаст параметр. - Чтобы написать выражение вручную (с
ИЛИ,ПОДОБНО, функциями), включите флажок «Произвольное» в строке условия.
Строки на вкладке «Условия» конструктор соединяет через И. Для ИЛИ нужна одна произвольная строка со скобками.
Как связать несколько условий: И, ИЛИ, НЕ
Логические операторы работают по приоритету: сначала НЕ, затем И, последним ИЛИ. Из-за этого запрос без скобок часто возвращает не то, что задумано.
Задача: проведённые документы, у которых контрагент — Альфа или Бета. Неверный вариант:
ГДЕ
Реализация.Проведен
И Реализация.Контрагент = &Альфа
ИЛИ Реализация.Контрагент = &Бета
Платформа прочитает это как «(проведён И Альфа) ИЛИ Бета». В выборку попадут непроведённые документы по Бете. Правильно — скобки:
ГДЕ
Реализация.Проведен
И (Реализация.Контрагент = &Альфа
ИЛИ Реализация.Контрагент = &Бета)
А ещё лучше — заменить цепочку ИЛИ по одному полю на В: Реализация.Контрагент В (&Альфа, &Бета). Короче, читается легче и не ломается при добавлении нового условия.
НЕ ставится перед любым выражением: НЕ Склад В (&Склады), НЕ Наименование ПОДОБНО "Архив%", НЕ Поле ЕСТЬ NULL (допустимо и Поле ЕСТЬ НЕ NULL).
Если в условии есть и И, и ИЛИ, всегда ставьте скобки, даже если приоритет вас устраивает. Через полгода коллега добавит строчку — и логика тихо поменяется.
Параметры в условиях запроса
Параметр в тексте обозначается амперсандом: &Контрагент. Значение задаётся до выполнения:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Контрагент = &Контрагент
| И Реализация.Организация В (&Организации)";
Запрос.УстановитьПараметр("Контрагент", Контрагент);
Запрос.УстановитьПараметр("Организации", МассивОрганизаций);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Ссылка);
КонецЦикла;
Почему параметр лучше, чем склейка строки вида "... = """ + Значение + """":
- ✅ ссылку на объект вообще нельзя вклеить в текст — только передать параметром;
- ✅ не нужно возиться с кавычками и форматом дат;
- ✅ один и тот же текст запроса работает с разными значениями.
Список значений и иерархия
Для оператора В (&Список) передайте Массив, СписокЗначений или колонку таблицы значений, выгруженную в массив через ВыгрузитьКолонку(). Пустой массив не ошибка: условие просто не найдёт ни одной строки.
В ИЕРАРХИИ нужен для иерархических справочников. Условие Номенклатура В ИЕРАРХИИ (&ГруппаКабели) вернёт и саму группу, и все вложенные подгруппы и элементы. Обычное Номенклатура.Родитель = &ГруппаКабели возьмёт только первый уровень.
Необязательный отбор
Частая задача: если пользователь выбрал склад — фильтровать по нему, если нет — показывать все. Вариант с флагом:
ГДЕ
(&БезОтбораПоСкладу ИЛИ Остатки.Склад = &Склад)
В коде: Запрос.УстановитьПараметр("БезОтбораПоСкладу", НЕ ЗначениеЗаполнено(Склад)). Для больших таблиц быстрее собрать текст условия в коде и добавлять строку И Склад = &Склад только при заполненном отборе: так СУБД получает простое условие и может использовать индекс.
Отбор по датам и периодам
Поле Дата у документа хранит дату и время. Поэтому Дата = &День почти никогда ничего не находит: документ проведён в 14:35, а параметр — 00:00:00.
Правильный отбор за период:
ГДЕ
Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаС));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаПо));
Если граница приходит из поля выбора даты без времени, без КонецДня() документы последнего дня выпадут из отчёта. Это самая частая причина «не сходится на одну дату».
Функции периода есть и внутри самого языка запросов:
| Задача | Выражение в запросе |
|---|---|
| Дата-константа | ДАТАВРЕМЯ(2025, 1, 1) |
| Начало месяца от поля | НАЧАЛОПЕРИОДА(Реализация.Дата, МЕСЯЦ) |
| Конец квартала от параметра | КОНЕЦПЕРИОДА(&Дата, КВАРТАЛ) |
| Сдвиг на 30 дней назад | ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -30) |
| Разница в днях | РАЗНОСТЬДАТ(Реализация.Дата, &Дата, ДЕНЬ) |
| Отбор по году | ГОД(Реализация.Дата) = 2025 |
Условие ГОД(Дата) = 2025 работает, но оборачивание поля функцией мешает СУБД использовать индекс по дате. На больших базах пишите диапазоном: Дата МЕЖДУ ДАТАВРЕМЯ(2025, 1, 1) И ДАТАВРЕМЯ(2025, 12, 31, 23, 59, 59).
Для виртуальных таблиц регистров (Остатки, Обороты, ОстаткиИОбороты) период задают не в ГДЕ, а первыми параметрами самой таблицы. Об этом — в разделе про сложные условия.
Ссылки, пустые значения и NULL
Здесь три разные сущности, и путать их нельзя.
Пустая ссылка — реквизит есть, но не заполнен. Сравнивают с предопределённым значением через ЗНАЧЕНИЕ():
ГДЕ
Реализация.Договор = ЗНАЧЕНИЕ(Справочник.ДоговорыКонтрагентов.ПустаяСсылка)
Через ЗНАЧЕНИЕ() в текст запроса подставляют и другие известные заранее значения: элементы перечислений, предопределённые элементы справочников и счета. Например, ЗНАЧЕНИЕ(Перечисление.ЮридическоеФизическоеЛицо.ЮридическоеЛицо) или ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.Касса). Параметр для таких констант заводить не нужно.
Пустая дата — ДАТАВРЕМЯ(1, 1, 1). Пустая строка — "". Пустое число — 0.
NULL — значения нет вообще. Он появляется, когда при левом соединении справа не нашлось пары, или когда поле разыменовывается через ссылку другого типа. Сравнение = NULL не работает
, нужен оператор ЕСТЬ NULL:
ВЫБРАТЬ
Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ ЦеныТоваров КАК Цены
ПО Номенклатура.Ссылка = Цены.Номенклатура
ГДЕ
Цены.Цена ЕСТЬ NULL
Так находят товары, для которых нет цены (здесь ЦеныТоваров — временная таблица, подготовленная выше). Чтобы превратить NULL в ноль для расчётов, есть функция ЕСТЬNULL(Цены.Цена, 0).
Проверка «поле не заполнено» для реквизита, который может быть и пустой ссылкой, и NULL (например, после соединения): ЕСТЬNULL(Поле, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)) = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка).
Составной тип и оператор ССЫЛКА
У регистров поле Регистратор может ссылаться на документы разных видов. Чтобы оставить только реализации, пишут Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг. Функция ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.РеализацияТоваровУслуг) даёт тот же результат, но ССЫЛКА короче.
Сложные условия: подзапросы, временные таблицы, соединения
Условие с подзапросом
Оператор В принимает не только список, но и вложенный запрос:
ГДЕ
Контрагенты.Ссылка В
(ВЫБРАТЬ
Реализация.Контрагент
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
И Реализация.Дата >= &Начало)
Получатся контрагенты, которым была хотя бы одна отгрузка с указанной даты. НЕ В (ВЫБРАТЬ …) — наоборот, те, кому отгрузок не было.
Временная таблица вместо тяжёлого подзапроса
Если подзапрос большой или нужен дважды, вынесите его во временную таблицу в пакете запросов:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Реализация.Контрагент КАК Контрагент
ПОМЕСТИТЬ ВТ_Покупатели
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
И Реализация.Дата МЕЖДУ &Начало И &Конец
ИНДЕКСИРОВАТЬ ПО
Контрагент
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Контрагенты.Ссылка
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.Ссылка В
(ВЫБРАТЬ ВТ.Контрагент ИЗ ВТ_Покупатели КАК ВТ)
Пакетные запросы разделяются точкой с запятой; строка из слэшей — просто комментарий, который вставляет конструктор. Временные таблицы живут, пока существует менеджер временных таблиц запроса.
Условие внутри параметров виртуальной таблицы
Это главный приём оптимизации, который знает каждый разработчик 1С. Отбор для Остатки и Обороты пишут в скобках самой таблицы:
ВЫБРАТЬ
Остатки.Субконто1,
Остатки.СуммаОстаток
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(
&Дата,
Счет В ИЕРАРХИИ (ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.РасчетыСПокупателями)),
,
Организация = &Организация) КАК Остатки
Если перенести Организация = &Организация в ГДЕ, результат будет тем же, но платформа сначала посчитает остатки по всем организациям и только потом отбросит лишнее. В параметре отбор срабатывает до расчёта — на большой базе разница бывает в разы.
Условие соединения и ИМЕЮЩИЕ
- 🔸 Условие в
ПОпри левом соединении фильтрует только правую таблицу, строки левой остаются. То же условие вГДЕотсечёт строки, где справа NULL, и левое соединение фактически станет внутренним. - 🔸
ИМЕЮЩИЕ— условие на итог группировки.ГДЕотбирает строки до группировки,ИМЕЮЩИЕ— группы после:СГРУППИРОВАТЬ ПО Контрагент ИМЕЮЩИЕ СУММА(СуммаДокумента) > 100000. - 🔸
ВЫБОРдопустим и в условии:ГДЕ ВЫБОР КОГДА &ТолькоКрупные ТОГДА СуммаДокумента > 100000 ИНАЧЕ ИСТИНА КОНЕЦ.
Почему условие не срабатывает или тормозит
Ещё две вещи, которые не дают ошибки, но портят результат:
- Разыменование через точку в условии.
ГДЕ Реализация.Контрагент.ИНН = &ИННвыглядит невинно, но платформа неявно подключает таблицу контрагентов. Если поле составного типа, соединений будет по одному на каждый тип. Для отбора по реквизиту лучше сначала найти ссылку на контрагента, а в запрос передать её. - Условие на поле, которого нет у части строк. В объединённых запросах каждое
ОБЪЕДИНИТЬимеет свою секциюГДЕ. Условие из первой части на вторую не распространяется.
Проверять запросы удобно в консоли запросов (обработка входит в набор инструментов разработчика или в состав некоторых конфигураций): туда вставляют текст, заполняют параметры и сразу видят результат и время выполнения.