Запросы в 1С:Предприятие — это мощный инструмент для работы с данными, но их эффективность напрямую зависит от правильного использования условий. Без грамотно составленных фильтров даже простой отчёт может вернуть тысячи ненужных строк, а сложный анализ — превратиться в бесконечную обработку данных. В этой статье разберём, как задавать условия в запросах 1С 8.3 и 1С 8.2, начиная с базового синтаксиса и заканчивая продвинутыми техниками оптимизации.
Вы научитесь использовать операторы ГДЕ, И, ИЛИ, работать с параметрами, подзапросами и динамическими условиями. Особое внимание уделим типичным ошибкам, которые приводят к медленной работе запросов или некорректным результатам. Материал будет полезен как начинающим разработчикам, так и опытным программистам, которые хотят систематизировать знания.
Базовый синтаксис условия ГДЕ в 1С
Оператор ГДЕ (или WHERE в англоязычной нотации) — основа фильтрации данных в запросах 1С. Он позволяет отбирать строки, соответствующие заданным критериям. Простейший пример:
ВЫБРАТЬ
Номенклатура.Наименование,
Номенклатура.Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ПометкаУдаления = ЛОЖЬ
Здесь условие отбирает только не помеченные на удаление элементы справочника. Обратите внимание на ключевые моменты:
- 🔹 Сравнение значений производится с помощью операторов
=,<>(не равно),>,<и их комбинаций. - 🔹 Логические значения в 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для проверки существования связанных записей. - 🔹 Для сравнения с агрегированными данными (например, суммой) используйте
ВЫБРАТЬ ... В (). - 🔹 Подзапросы в условии
ГДЕдолжны возвращать одну колонку.
Пример с агрегатной функцией:
ГДЕ Документ.СуммаДокумента > (
ВЫБРАТЬ СУММА(СуммаДокумента) КАК СредняяСумма
ИЗ Документ.РеализацияТоваровУслуг
)
⚠️ Внимание: Подзапросы в условиях ГДЕ могут существенно замедлить выполнение, если они коррелированы (ссылаются на поля внешнего запроса). В таких случаях рассмотрите возможность использования временных таблиц.
☑️ Оптимизация подзапросов
Динамическое формирование условий
Иногда условия запроса зависят от пользовательских настроек или внешних данных. В таких случаях строку запроса можно формировать динамически.
Пример: добавление условия по организации, если она выбрана:
ТекстЗапроса = "
|ВЫБРАТЬ
| Документ.Номер,
| Документ.Дата
|ИЗ
| Документ.ЗаказПокупателя КАК Документ
|";
Если ЗначениеЗаполнено(Организация) Тогда
ТекстЗапроса = ТекстЗапроса + "
|ГДЕ
| Документ.Организация = &Организация
";
КонецЕсли;
Для безопасного добавления параметров используйте метод ДобавитьПараметр():
Если ЗначениеЗаполнено(ДатаНачала) Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ДатаНачала", "Документ.Дата >= &ДатаНачала");
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
КонецЕсли;
Альтернативный подход — использование конструкции ВЫРАЗИТЬ() для условной логики прямо в запросе:
ВЫБРАТЬ
Документ.Номер,
ВЫРАЗИТЬ(ЕСТЬNULL(Документ.Комментарий, "") КАК СТРОКА(50)) КАК Комментарий
ИЗ
Документ.ЗаказПокупателя КАК Документ
Преимущества динамического формирования:
- 🔹 Гибкость: один запрос адаптируется под разные сценарии.
- 🔹 Производительность: исключаются ненужные условия.
Недостатки:
- 🔹 Сложность поддержки кода.
- 🔹 Риск SQL-инъекций при некорректной обработке параметров.
Динамическое формирование условий удобно для отчётов с большим количеством опциональных фильтров, но требует тщательной проверки на ошибки и уязвимости.
Оптимизация условий: индексы и планы выполнения
Неправильно составленные условия могут привести к полному сканированию таблиц (table scan), что критично для больших баз данных. Чтобы этого избежать, следуйте правилам:
- 🔢 Используйте индексированные поля в условиях. В 1С индексы автоматически создаются для полей с типом "Ссылка", "Дата", а также для полей, участвующих в соединениях.
- 🔢 Избегайте функций над полями в условиях. Например, вместо:
ГДЕ ГОД(Документ.Дата) = 2023используйте:
ГДЕ Документ.Дата МЕЖДУ '20230101' И '20231231' - 🔢 Для текстовых полей используйте префиксный поиск (
НАЧИНАЕТСЯилиПОДОБНО "текст%"), а неСОДЕРЖИТ.
Чтобы проверить, как 1С выполняет запрос, используйте план выполнения:
Объяснить = Запрос.Выполнить().ВыгрузитьПланВременнойТаблицы();
Объяснить.Выгрузить();
Признаки неоптимального плана:
- 🔹
Полное сканирование(Seq Scan) вместо использования индекса. - 🔹 Большое количество операций
СортировкаилиХэш-соединение. - 🔹 Высокая оценка стоимости (cost) в плане.
⚠️ Внимание: В последних версиях 1С (начиная с платформы 8.3.20) оптимизатор запросов стал "умнее", но всё равно требует контроля. Например, он может не использовать индекс, если статистика по таблице устарела. В таких случаях поможет вызов ОБНОВИТЬСТАТИСТИКУ().
Типичные ошибки и как их избежать
Даже опытные разработчики допускают ошибки при составлении условий. Рассмотрим наиболее распространённые:
| Ошибка | Причина | Как исправить |
|---|---|---|
| Сравнение разных типов | Сравнение строки с числом или даты со строкой | Явно приводите типы: ЧИСЛО(Поле) = 100 |
| Неучтённые NULL | Поля могут содержать NULL, что ломает логику |
Используйте ЗНАЧЕНИЕ ЗАПОЛНЕНО() или ЕСТЬNULL() |
| Избыточные условия | Условия, которые всегда истинны или ложны | Упрощайте логику, убирайте лишние проверки |
| Неправильный приоритет операторов | И выполняется раньше ИЛИ |
Используйте скобки для явного указания приоритета |
Пример ошибки с типами:
ГДЕ Документ.Номер = "000123" // Сравнивается строка с числом!
Правильный вариант:
ГДЕ Документ.Номер = ЧИСЛО("000123") // Или СТРОКА(Документ.Номер) = "000123"
Ещё одна частая проблема — игнорирование регистра при сравнении строк:
ГДЕ Наименование = "товар" // Не найдёт "Товар" или "ТОВАР"
Решение:
ГДЕ ВРЕГ(Наименование) = ВРЕГ("товар")
Для проверки на NULL никогда не используйте конструкцию = NULL. Вместо этого:
ГДЕ Документ.Поле ЕСТЬ NULL // Правильно
ГДЕ Документ.Поле = NULL // Ошибка!
FAQ: Ответы на частые вопросы
Как в условии запроса проверить, что поле содержит одно из нескольких значений?
Используйте оператор В():
ГДЕ Номенклатура.ВидНоменклатуры В (&МассивВидов)
где &МассивВидов — это массив или список значений, переданный как параметр. Например:
МассивВидов = Новый Массив;
МассивВидов.Добавить(ВидНоменклатуры.Товар);
МассивВидов.Добавить(ВидНоменклатуры.Услуга);
Запрос.УстановитьПараметр("МассивВидов", МассивВидов);
Можно ли в условии запроса использовать свои функции?
Нет, в тексте запроса можно использовать только встроенные функции 1С (например, НАЧИНАЕТСЯ(), ЗНАЧЕНИЕЗАПОЛНЕНО()). Для использования своих функций придётся:
- Выгрузить данные во временную таблицу.
- Обработать их в коде 1С с помощью своей функции.
- При необходимости вернуть результат в новый запрос.
Исключение — функции, зарегистрированные как расширяющие язык запросов (доступно в последних версиях платформы).
Как оптимизировать запрос с большим количеством условий?
Следуйте этим рекомендациям:
- 🔹 Перенесите статичные условия (например, по организации) в начало запроса.
- 🔹 Разбейте сложный запрос на несколько простых с использованием временных таблиц.
- 🔹 Замените подзапросы в
ГДЕна соединения (ЛЕВОЕ СОЕДИНЕНИЕ,ВНУТРЕННЕЕ СОЕДИНЕНИЕ). - 🔹 Используйте
ИНДЕКСИРОВАТЬ ПОдля указания полей, по которым должен строиться индекс.
Пример оптимизированного запроса:
ВЫБРАТЬ
Документ.Номер
ИЗ
Документ.ЗаказПокупателя КАК Документ
ГДЕ
Документ.Организация = &Организация
И Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
ИНДЕКСИРОВАТЬ ПО
Организация,
Дата
Почему запрос игнорирует моё условие по дате?
Частые причины:
- Неверный формат даты: Убедитесь, что передаёте дату как
Дата, а не строку. Например:Запрос.УстановитьПараметр("ДатаНачала", '20230101'); // Ошибка!Запрос.УстановитьПараметр("ДатаНачала", Дата(2023, 1, 1)); // Правильно
- Проблемы с временной зоной: Если в базе хранятся даты с временем, а вы сравниваете только с датой, используйте:
ГДЕ НачалоПериода(Документ.Дата, ДЕНЬ) = &ДатаНачала - Неучтённое время: Для диапазона дат всегда используйте:
ГДЕ Документ.Дата >= НачалоДня(&ДатаНачала)И Документ.Дата < КонецДня(&ДатаОкончания)
Как задать условие по связанному справочнику?
Для фильтрации по полям связанного справочника используйте точечную нотацию. Например, чтобы отобрать документы по виду номенклатуры:
ВЫБРАТЬ
Документ.Номер
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Номенклатура.ВидНоменклатуры = &ВидНоменклатуры
Если связь многоуровневая (например, номенклатура → вид номенклатуры → категория), используйте цепочку:
ГДЕ Документ.Номенклатура.ВидНоменклатуры.Категория = &Категория
⚠️ Внимание: Фильтрация по связанным справочникам может быть медленной, если поля не проиндексированы. В таких случаях рассмотрите денормализацию данных или использование регистров сведений.