Разработка эффективных механизмов выборки данных в платформе 1С:Предприятие 8 невозможна без глубокого понимания того, как формируются условия фильтрации. Именно блок ГДЕ определяет, какие записи попадут в результирующий набор, и от его корректности напрямую зависит производительность всей системы. Неправильно написанное условие может привести к полному сканированию таблиц, что недопустимо в высоконагруженных конфигурациях.

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

Базовый синтаксис оператора ГДЕ

Любой запрос к базе данных в 1С начинается с ключевого слова ВЫБРАТЬ, однако смысловую нагрузку несет именно секция ГДЕ. Здесь размещаются логические выражения, которые должны возвращать булево значение Истина или Ложь для каждой строки виртуальной таблицы.

Операторы сравнения в языке запросов 1С практически идентичны тем, что используются в стандартном языке SQL, но имеют свои особенности в контексте типизированных данных платформы.

  • 🔍 Равно (=) — используется для точного совпадения значений полей с константами или параметрами.
  • 📉 Неравно (<>) — исключает записи, соответствующие заданному критерию.
  • 📏 Больше/Меньше (>, <) — применяются преимущественно для числовых полей и дат.
  • 📅 Диапазон (МЕЖДУ) — удобный способ задать промежуток значений без дублирования имени поля.

Если вы сравниваете поле ссылки с константой, система попытается привести типы. В случае неудачи приведения типов запись будет исключена из выборки или вызовет ошибку выполнения.

💡

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

Работа с логическими операторами И, ИЛИ, НЕ

Сложные условия фильтрации требуют комбинации простых выражений. Для этого в языке запросов 1С предусмотрены стандартные логические связки. Приоритет выполнения операций строго регламентирован: сначала вычисляются выражения в скобках, затем НЕ, далее И, и в последнюю очередь ИЛИ.

Использование скобок является обязательным при смешивании операторов И и ИЛИ в одном выражении. Без явного указания приоритета логика запроса может стать непредсказуемой, что приведет к выборке совершенно не тех данных, которые ожидал разработчик.

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

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

Справочник.Номенклатура.ЭтоГруппа = ЛОЖЬ

И Справочник.Номенклатура.Родитель = &Родитель

ИЛИ Справочник.Номенклатура.ВидНоменклатуры = &Вид

В данном случае условие сработает некорректно из-за приоритета И над ИЛИ. Система сначала выполнит связку ЭтоГруппа И Родитель, а затем результат объединит через ИЛИ с видом номенклатуры. Это приведет к тому, что будут выбраны все элементы указанного вида, даже если они являются группами или не принадлежат нужному родителю.

☑️ Проверка логических условий

Выполнено: 0 / 4

Особенности проверки на пустое значение (NULL)

Одной из самых частых причин появления ошибок в отчетах является некорректная обработка значений NULL. В 1С пустое значение не равно нулю, пустой строке или лжи. Это специальное состояние, означающее отсутствие данных.

Для проверки поля на заполненность используется специальный синтаксис ЕСТЬ NULL или его отрицание НЕ ЕСТЬ NULL. Попытка использовать операторы сравнения (например, Поле = NULL) всегда вернет ложь, так как NULL не сравним ни с чем, включая самого себя.

⚠️ Внимание: При работе с составными типами, где одно из допустимых значений — NULL, обычное сравнение может не сработать ожидаемым образом. Всегда используйте конструкцию ЕСТЬ NULL для явной проверки отсутствия значения.

Часто возникает необходимость выбрать записи, где поле либо равно конкретному значению, либо не заполнено вовсе. В таких случаях условия объединяются через ИЛИ:

ГДЕ

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

ИЛИ Документ.РеализацияТоваровУслуг.Контрагент ЕСТЬ NULL

Такой подход гарантирует, что вы получите все документы по указанному контрагенту, а также документы, где контрагент не был указан (если бизнес-логика это допускает).

Использование параметров и временных таблиц

Для повышения гибкости запросов и защиты от SQL-инъекций (хотя в 1С это менее актуально из-за архитектуры, но принцип параметризации важен для кэширования планов выполнения) следует использовать параметры. Они передаются в объект запроса через метод УстановитьПараметр() перед выполнением.

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

Тип параметра Пример использования в ГДЕ Особенности передачи
Строка Поле = &ИмяПараметра Регистронезависимое сравнение
Число Сумма > &МинСумма Точное числовое сравнение
Дата Дата МЕЖДУ &Начало И &Конец Включает время до миллисекунд
Ссылка Ссылка = &ДокументСсылка Сравнение уникальных идентификаторов

Если список значений для фильтрации динамически формируется в коде (например, список ID документов), передавать их как один параметр-массив напрямую в условие В нельзя. В таких случаях данные загружаются во временную таблицу, которая затем используется в основном запросе через соединение или вложенный запрос.

Как передать список значений в запрос?

Создайте временную таблицу через конструктор запроса или программно. Заполните её значениями из массива. В основном запросе используйте условие "Поле В (ВЫБРАТЬ Поле ИЗ ВременнаяТаблица)". Это обеспечит высокую производительность даже при тысячах значений.

Сравнение строк и чувствительность к регистру

При работе со строковыми полями в 1С важно учитывать настройки сравнения. По умолчанию в большинстве конфигураций сравнение строк в запросах является регистронезависимым. Это означает, что условие Наименование = "стол" найдет запись "Стол", "СТОЛ" и "стол".

Однако, если в метаданных объекта установлена галка "Различать регистр", поведение изменится. В этом случае для точного поиска необходимо учитывать регистр символов. Это часто используется для кодов номенклатуры или артикулов, где "abc" и "ABC" могут быть разными товарами.

Для явного управления сравнением можно использовать функции преобразования регистра, такие как СТРОКА() или специфические функции платформы, но лучше полагаться на настройки метаданных и тестировать запросы на реальных данных.

💡

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

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

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

Например, конструкция ГОД(Дата) = 2026 заставит систему просканировать всю таблицу, вычисляя год для каждой записи. Правильный подход — использовать диапазон дат:

ГДЕ

Дата >= НАЧАЛОГОДА(2026)

И Дата < НАЧАЛОГОДА(2026)

Такой запрос позволит СУБД использовать индекс по полю Дата, что ускорит выполнение в сотни раз на больших объемах данных.

⚠️ Внимание: Избегайте использования функций над полями таблицы в левой части оператора сравнения. Это правило ("SARGable queries") является золотым стандартом оптимизации запросов в любых СУБД, включая те, что используются в 1С.

Также стоит избегать условий ИЛИ между разными полями, если они не покрыты составным индексом. В таких случаях оптимизатор запросов может выбрать неэффективный план выполнения. Иногда выгоднее разбить запрос на два отдельных и объединить результаты через ОБЪЕДИНИТЬ ВСЕ.

📊 Какой тип условий вы используете чаще всего?
Точное совпадение (=)
Диапазон дат (МЕЖДУ)
Поиск по подстроке (ПОДОБНО)
Сложные логические связки

Частые ошибки и способы их устранения

Даже опытные разработчики допускают ошибки при формировании условий. Чаще всего проблемы возникают при работе со ссылками на удаленные объекты или при сравнении разнородных типов данных.

Если в условии используется ссылка на объект, который был помечен на удаление, результат сравнения может быть неожиданным. В 1С помеченные на удаление объекты физически остаются в базе до проведения процедуры удаления. Поэтому условие Ссылка = &Ссылка сработает даже для удаленного элемента, если вы не добавили проверку флага ЭтоУдаление.

Еще одна распространенная проблема — сравнение составных типов, где типы не совместимы. Например, попытка сравнить числовое поле со строкой без явного приведения типов приведет к тому, что условие всегда будет ложным. Платформа 1С строго следит за типами данных в запросах.

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

Проверьте типы данных сравниваемых полей. Убедитесь, что в параметрах переданы значения корректного типа. Проверьте наличие пробелов в строковых полях (используйте функцию СОКРЛ/СОКРП). Также убедитесь, что данные не помечены на удаление, если это влияет на вашу выборку.

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

Да, язык запросов 1С поддерживает вложенные запросы. Вы можете использовать конструкцию Поле В (ВЫБРАТЬ..) или сравнивать поле с результатом скалярного подзапроса. Это мощный инструмент для фильтрации по данным из других таблиц без явных соединений.

Как проверить, используется ли индекс при выполнении запроса?

В режиме предприятия откройте консоль запросов или используйте отладчик. При выполнении запроса можно посмотреть план выполнения (в некоторых версиях платформы и инструментах администрирования). Если видите оператор "Table Scan" вместо "Index Seek", значит индекс не используется.

В чем разница между ПустаяСсылка() и NULL?

NULL означает, что в поле вообще нет значения. ПустаяСсылка() — это конкретное значение ссылки, указывающее на несуществующий объект (обычно все нули в GUID). В условиях ГДЕ это разные сущности: Поле ЕСТЬ NULL и Поле = ПустаяСсылка() дадут разные результаты.