Разработка эффективных отчетов и обработок в платформе 1С:Предприятие 8 невозможна без глубокого понимания языка запросов. Центральным элементом любого выборки данных является фильтрация, которая позволяет извлекать из базы только ту информацию, которая соответствует конкретным критериям. Правильное наложение условий напрямую влияет на производительность системы, так как отсечение лишних записей на уровне СУБД снижает нагрузку на память и процессор.
Многие начинающие разработчики сталкиваются с трудностями при построении сложных логических конструкций или работе с временными интервалами. Ошибки в синтаксисе могут привести к тому, что отчет будет работать часами или выдавать некорректные результаты. В этой статье мы детально разберем механизмы фильтрации, от простых сравнений до продвинутых техник использования параметров и ссылок на таблицы.
Базовый синтаксис оператора ВЫБРАТЬ и ГДЕ
Основной блок, отвечающий за фильтрацию данных в языке запросов 1С, располагается после ключевого слова ГДЕ. Именно здесь формулируются логические выражения, которые должны быть истинными для каждой строки результирующей выборки. Синтаксис позволяет комбинировать различные поля таблицы с константами, другими полями или результатами вычислений.
При написании условия важно соблюдать приоритет операций. Логические операторы И, ИЛИ и НЕ работают по стандартным правилам булевой алгебры. Если вы хотите объединить несколько критериев, использование круглых скобок является обязательным для однозначной интерпретации логики запросом.
Рассмотрим простой пример выборки номенклатуры с определенным видом. Здесь мы используем прямое сравнение строкового значения с полем справочника.
ВЫБРАТЬ
Номенклатура.Ссылка,
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ВидНоменклатуры = ЗНАЧЕНИЕ(Справочник.ВидыНоменклатуры.Товар)
Обратите внимание на использование макроса ЗНАЧЕНИЕ. Это стандартный способ подстановки предопределенных элементов метаданных прямо в текст запроса. Такой подход гарантирует, что запрос будет работать корректно независимо от внутренней идентификатора элемента в конкретной базе данных.
⚠️ Внимание: При сравнении строковых полей регистр символов может иметь значение в зависимости от настроекCollation вашей СУБД. В 1С обычно используется регистронезависимое сравнение, но при работе с внешними источниками данных через
ОТКРЫТЫЙ ЗАПРОСэто поведение может отличаться.
Используйте автоподстановку полей в Конструкторе запросов, чтобы избежать опечаток в именах таблиц и полей. Это также помогает корректно проставлять псевдонимы.
Работа с параметрами и динамическая фильтрация
В реальных прикладных задачах жестко заданные условия в тексте запроса встречаются редко. Гораздо чаще требуется гибкая фильтрация, зависящая от ввода пользователя или контекста выполнения программы. Для этих целей в 1С используются параметры запроса, которые обозначаются символом & перед именем.
Параметры позволяют передавать значения из кода встроенного языка в текст запроса в момент его выполнения. Это не только упрощает поддержку кода, но и защищает от SQL-инъекций при работе с некоторыми типами СУБД, хотя в контексте 1С это в первую очередь вопрос архитектуры приложения.
- 🔹 Передача конкретного значения:
&ПериодНачала - 🔹 Передача списка значений:
&СписокКонтрагентов - 🔹 Передача булевого флага:
&ПоказыватьТолькоПроведенные - 🔹 Использование NULL:
ЕСТЬNULL(&Параметр, ЗначениеПоУмолчанию)
Особое внимание следует уделить обработке случаев, когда параметр может быть не заполнен. Часто возникает ситуация, когда фильтр должен применяться только если пользователь выбрал значение в форме отчета. Для этого используется функция ЕСТЬNULL или сравнение параметра с самим собой.
ВЫБРАТЬ
Продажи.Контрагент,
Продажи.Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Контрагент = ЕСТЬNULL(&Контрагент, Продажи.Контрагент)
В данном примере, если параметр &Контрагент не заполнен (равен NULL), условие превращается в сравнение поля с самим собой, что всегда истинно. Таким образом, фильтр эффективно отключается без необходимости менять текст запроса программно.
Фильтрация по датам и временным интервалам
Работа с датами является одной из самых частых задач в учетных системах. В 1С тип Дата включает в себя как календарную дату, так и время с точностью до секунды. Это создает определенные нюансы при наложении условий, особенно когда требуется выбрать данные за целый день или период.
Если вы просто укажете дату начала и конца периода в условии МЕЖДУ, вы можете случайно отсечь документы, созданные в конце последнего дня периода (например, в 23:59:59). Чтобы избежать этого, необходимо корректно формировать границы интервала.
| Тип условия | Синтаксис | Описание поведения |
|---|---|---|
| Точное время | Дата = &Дата |
Выберет записи только с точным совпадением времени |
| Начало дня | НАЧАЛОДНЯ(&Дата) |
Усекает время до 00:00:00 |
| Конец дня | КОНЕЦДНЯ(&Дата) |
Усекает время до 23:59:59 |
| Период | МЕЖДУ &Начало И &Конец |
Включает обе границы интервала |
Для выборки данных за весь выбранный день рекомендуется использовать конструкцию, где конечная граница сдвигается на начало следующего дня, но само условие делается строгим меньше. Либо использовать специальные функции работы с периодами регистров, если речь идет о срезах.
При фильтрации по периоду в регистрах накопления часто используется ключевое слово ПЕРИОД в начале запроса. Это указывает движку 1С, что нужно учитывать только движения, попавшие в указанный временной диапазон, что может существенно оптимизировать выполнение.
⚠️ Внимание: Функции преобразования даты, такие как
НАЧАЛОДНЯ, при использовании в условииГДЕнад полем таблицы могут привести к полному сканированию индекса. Лучше вычислять границы периода в коде перед запуском запроса и передавать их как готовые параметры.
Почему не стоит использовать функции над полями в WHERE?
Применение функций к полям таблицы (например, ГОД(Дата) = 2026) запрещает СУБД использовать индекс по полю Дата. Это заставляет систему перебирать все записи таблицы, что критически замедляет работу на больших объемах данных.
Сложные условия и вложенные запросы
Когда простой фильтрации по полям текущей таблицы недостаточно, на помощь приходят вложенные запросы. Они позволяют сформировать промежуточный набор данных, который затем используется как источник для основного запроса или как условие отбора.
Оператор ПОДОБНО является мощным инструментом для текстового поиска, поддерживающим символы подстановки % (любая последовательность) и _ (один символ). Однако его следует использовать с осторожностью, так как поиск по шаблону с началом с процента (например, %текст) крайне ресурсоемок.
Часто возникает необходимость отфильтровать записи на основе наличия или отсутствия связанных данных в других таблицах. Для этого используются конструкции ПОДВИДЖОТОВИТЬ или проверка на вхождение в подзапрос через оператор В.
ВЫБРАТЬ
Номенклатура.Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Ссылка В
(ВЫБРАТЬ
Остатки.Номенклатура
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ГДЕ
Остатки.Количество > 0)
Такой подход обеспечивает высокую читаемость кода и позволяет инкапсулировать сложную логику отбора внутри вложенного блока.
Использование оператора В с вложенным запросом часто эффективнее, чем соединение таблиц через СОЕДИНЕНИЕ, когда нужно просто проверить факт наличия связи без вывода полей связанной таблицы.
Оптимизация условий и работа с индексами
Написание работающего запроса — это только половина дела. Вторая, не менее важная часть, — обеспечение его быстродействия. Правильно наложенное условие должно использовать существующие индексы в базе данных. В 1С индексы создаются автоматически для полей, участвующих в связях, измерениях регистров и ключевых полях справочников.
Чтобы условие могло воспользоваться индексом, оно должно быть "простым". Это означает, что поле таблицы должно стоять слева от знака сравнения, а справа должно быть значение, параметр или поле другой таблицы, но не результат функции или вычисления.
- ✅
ГДЕ Поле = &Параметр— использует индекс - ✅
ГДЕ Поле > 100— использует индекс - ❌
ГДЕ СУММА(Поле) > 100— агрегатные функции в WHERE запрещены - ❌
ГДЕ ЛЕВСИМВ(Поле, 3) = "АБВ"— функция над полем ломает индекс
Анализ выполнения запроса через консоль запросов или технологический журнал позволяет увидеть, какие индексы были использованы. Если вы видите полное сканирование таблицы (Table Scan) там, где ожидается поиск по индексу, стоит пересмотреть структуру условия.
Также стоит учитывать селективность условия. Фильтрация по полю с низкой уникальностью (например, "Пол" или "Валюта", если их всего 3 вида) может оказаться менее эффективной, чем полный проход, если выбирается большая часть записей. Оптимизатор 1С сам принимает решение, но понимание этого принципа помогает писать более предсказуемый код.
⚠️ Внимание: Составные индексы работают только если условие наложено на первое поле индекса. Если ваш индекс состоит из полей (А, Б), то условие только по полю Б не сможет использовать этот индекс эффективно.
☑️ Проверка оптимизации запроса
Типичные ошибки и способы их устранения
Даже опытные разработчики допускают ошибки при формировании условий. Одной из самых распространенных является попытка сравнить разнотипные данные без явного приведения типов. Например, сравнение строки и числа может привести к непредсказуемым результатам или ошибке выполнения.
Другая частая проблема — ошибка "Таблица не найдена" или "Поле не найдено". Это обычно происходит, когда в условии используется псевдоним таблицы, который был определен в другом месте, или когда поле относится к таблице, не введенной в контекст запроса через ИЗ или СОЕДИНЕНИЕ.
При работе с объединениями (ОБЪЕДИНИТЬ) Если же нужно отфильтровать каждую часть объединения отдельно, условие должно быть внутри каждой части до ключевого слова ОБЪЕДИНИТЬ.
// Ошибка: Фильтр применится только ко второй части, если написать так:
ВЫБРАТЬ Поле ИЗ Таблица1
ОБЪЕДИНИТЬ
ВЫБРАТЬ Поле ИЗ Таблица2
ГДЕ Поле > 10
// Правильно: Фильтр для каждой части
ВЫБРАТЬ Поле ИЗ Таблица1 ГДЕ Поле > 10
ОБЪЕДИНИТЬ
ВЫБРАТЬ Поле ИЗ Таблица2 ГДЕ Поле > 10
Всегда проверяйте типы данных параметров. Передача строки туда, где ожидается число, заставит систему выполнять неявное преобразование, что может замедлить запрос или вызвать ошибку при некорректном содержимом строки.
Если запрос выдает ошибку синтаксиса, попробуйте скомпилировать его в Конструкторе запросов. Он часто указывает на конкретную строку и символ, где нарушена грамматика, что сложно заметить в тексте кода.
Можно ли использовать оператор LIKE в 1С?
Да, аналогом оператора LIKE из SQL в языке запросов 1С является оператор ПОДОБНО. Он поддерживает те же символы подстановки: % заменяет любую последовательность символов, а _ заменяет ровно один символ. Синтаксис: Поле ПОДОБНО "%образец%".
Как передать список значений в параметр запроса?
Для передачи списка используется тип значения СписокЗначений во встроенном языке. В запросе параметр объявляется как обычно, а в код 1С вы создаете объект Новый СписокЗначений, заполняете его и присваиваете параметру. В условии запроса это работает как множественное сравнение (IN).
В чем разница между ГДЕ и ИМЕЕТСЯ?
Оператор ГДЕ фильтрует строки до группировки и агрегации. Оператор ИМЕЕТСЯ (аналог SQL HAVING) фильтрует уже сгруппированные результаты. ИМЕЕТСЯ можно использовать только вместе с СГРУППИРОВАТЬ ПО и только для полей, входящих в агрегатные функции или группу.
Почему запрос не использует индекс по дате?
Чаще всего причина в том, что к полю даты применена функция (например, ГОД(Дата) или НАЧАЛОДНЯ(Дата)) непосредственно в условии ГДЕ. Это делает индекс непригодным для поиска. Решение: вычислять границы периода заранее в коде и передавать их параметрами.
Как проверить пустое значение в условии?
Для проверки на неопределенное значение (NULL) в 1С используется оператор ЕСТЬ NULL. Пример: ГДЕ Поле ЕСТЬ NULL. Для проверки на заполненность используется НЕ ЕСТЬ NULL. Пустая строка и NULL — это разные вещи в контексте базы данных.