Разработка и Конфигурация · 13 мин
Как использовать функции в запросе 1С
Как использовать функции в запросе 1С: агрегатные функции, работа со строками и датами, ПОДСТРОКА, РАЗНОСТЬДАТ, ВЫРАЗИТЬ, примеры кода и типичные ошибки.
Язык запросов 1С — это не только выборка полей из таблиц. Встроенные функции позволяют прямо в тексте запроса суммировать обороты, обрезать строки, вычислять разницу между датами, приводить типы и подставлять значения вместо NULL. Грамотное использование функций сокращает объём построчной обработки результата в коде и снижает нагрузку на сервер, потому что вычисления выполняются на уровне СУБД.
Главное, что нужно понять сразу: функции в запросе делятся на два класса. Агрегатные функции — СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ — сворачивают группу строк в одно значение. Функции обработки значений — ПОДСТРОКА, ДАТАВРЕМЯ, РАЗНОСТЬДАТ, ВЫРАЗИТЬ, ЕСТЬNULL и другие — применяются к каждой строке отдельно и не требуют группировки. Смешивать эти классы без понимания их поведения — самая частая причина ошибок «Неверные параметры агрегатной функции» и неожиданных результатов.
Ниже разобраны оба класса с конкретными примерами синтаксиса, ограничениями платформы и типичными ошибками, которые встречаются у разработчиков при переносе логики из кода в запрос.
Агрегатные функции: СУММА, КОЛИЧЕСТВО, МАКСИМУМ и группировка
Агрегатные функции вычисляют одно значение по набору строк. Если в запросе есть хотя бы одна агрегатная функция, все остальные поля в списке выборки обязаны либо входить в предложение СГРУППИРОВАТЬ ПО, либо тоже быть обёрнуты в агрегат. Иначе конструктор запроса выдаст ошибку ещё на этапе проверки текста.
Типичный пример — сумма продаж по контрагентам:
ВЫБРАТЬ
Продажи.Контрагент КАК Контрагент,
СУММА(Продажи.СуммаОборот) КАК СуммаПродаж,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Продажи.Регистратор) КАК ЧислоДокументов
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
Обратите внимание на конструкцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле): она считает уникальные значения, а не все строки. Без ключевого слова РАЗЛИЧНЫЕ вы получите количество строк в группе, что при детальных таблицах даст завышенные цифры. Это одна из самых коварных ошибок — запрос выполняется без предупреждений, но числа неверные.
Функции МИНИМУМ и МАКСИМУМ работают не только с числами, но и с датами и строками — удобно, когда нужно найти первую или последнюю дату документа по клиенту. СРЕДНЕЕ считает среднее арифметическое по непустым значениям: строки, где поле равно NULL, в расчёт не берутся, и это нужно учитывать при интерпретации результата.
Функции работы со строками: ПОДСТРОКА и её ограничения
Из строковых функций в языке запросов доступна фактически одна — ПОДСТРОКА(Строка, НачальнаяПозиция, Длина). Она возвращает фрагмент строки, начиная с указанной позиции (нумерация с единицы). Полного набора функций вроде замены, переворота или поиска подстроки в языке запросов нет — это принципиальное ограничение платформы.
ВЫБРАТЬ
ПОДСТРОКА(Номенклатура.Артикул, 1, 3) КАК ПрефиксАртикула,
Номенклатура.Ссылка КАК Товар
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
ПОДСТРОКА(Номенклатура.Артикул, 1, 2) = "AB"
Для поиска по вхождению подстроки вместо функций используется оператор ПОДОБНО с шаблоном: ГДЕ Наименование ПОДОБНО "%кабель%". Символ процента заменяет любую последовательность символов, подчёркивание — один символ. Спецсимволы в шаблоне экранируются через конструкцию СПЕЦСИМВОЛ.
Практический вывод: если задача требует сложной строковой логики — разбора ФИО, нормализации телефонов, замены символов — её лучше выполнять в коде после выборки или на этапе записи данных, а не пытаться эмулировать в запросе вложенными ПОДСТРОКА. Такие конструкции плохо читаются и не оптимизируются СУБД.
Функции работы с датами: ДАТАВРЕМЯ, РАЗНОСТЬДАТ, НАЧАЛОПЕРИОДА
Для формирования константной даты в запросе используется функция ДАТАВРЕМЯ(Год, Месяц, День, Час, Минута, Секунда). Часы, минуты и секунды можно опустить — тогда получится начало дня. Пустая дата записывается как ДАТАВРЕМЯ(1, 1, 1). Литералы даты в кавычках запрос не принимает — попытка сравнить поле со строкой вида «01.01.2026» даст ошибку несоответствия типов.
Функция РАЗНОСТЬДАТ(Дата1, Дата2, Единица) возвращает разницу между двумя датами в заданных единицах: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Типичный сценарий — расчёт просрочки по документам:
ВЫБРАТЬ
Заказы.Ссылка КАК Заказ,
РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
ИЗ
Документ.ЗаказКлиента КАК Заказы
ГДЕ
РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) > 3
Функции НАЧАЛОПЕРИОДА(Дата, Период) и КОНЕЦПЕРИОДА(Дата, Период) приводят дату к границе указанного интервала — дня, недели, месяца, квартала, года. Это удобно для группировки оборотов по месяцам без виртуальных таблиц: группируете по НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и получаете помесячную аналитику. Учтите, что КОНЕЦПЕРИОДА для типа Дата с точностью до секунды возвращает последнюю секунду периода, что важно при сравнениях на «меньше или равно».
Функция ДОБАВИТЬКДАТЕ(Дата, Единица, Количество) сдвигает дату на заданное число единиц — например, ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1) вернёт ту же дату месяц назад. Это избавляет от вычисления границ периода в коде и передачи лишних параметров.
- 1Передайте в запрос параметр &ТекущаяДата — функции «текущая дата» в языке запросов нет, её подставляют из кода
- 2В списке выборки напишите РАЗНОСТЬДАТ(ДатаДокумента, &ТекущаяДата, ДЕНЬ) с понятным псевдонимом
- 3Добавьте условие ГДЕ на ту же конструкцию, чтобы отсечь непросроченные документы
- 4Проверьте результат на документе с известной датой — разница должна совпасть с расчётом вручную
Приведение типов: ВЫРАЗИТЬ и работа с составными полями
Функция ВЫРАЗИТЬ(Поле КАК Тип) приводит значение к указанному типу. Основные сценарии: уточнение составного типа (например, поле, которое может хранить и контрагента, и физлицо), округление числа до нужной разрядности и обрезка строки неограниченной длины перед соединением таблиц.
ВЫБРАТЬ
ВЫРАЗИТЬ(Расчёты.Плательщик КАК Справочник.Контрагенты) КАК Контрагент,
ВЫРАЗИТЬ(Расчёты.Сумма КАК ЧИСЛО(15, 2)) КАК Сумма
ИЗ
РегистрНакопления.Расчёты КАК Расчёты
Практическое правило: при соединении таблиц по полям составного типа или по строкам неограниченной длины предварительно приведите обе стороны к одному типу через ВЫРАЗИТЬ. Иначе соединение может вернуть пустой результат или работать медленно, потому что СУБД не сможет сопоставить типы и применить индекс.
Ещё одна частая задача — проверка типа значения без приведения. Для этого используется не функция, а оператор ССЫЛКА: ГДЕ Поле ССЫЛКА Справочник.Контрагенты. А для получения текстового представления типа есть функция ТИПЗНАЧЕНИЯ(Поле), которую удобно сравнивать с конструкцией ТИП(Справочник.Контрагенты).
ЕСТЬNULL и обработка пустых значений
NULL в запросах 1С появляется при левых соединениях, когда в присоединяемой таблице нет подходящей строки, а также в необязательных реквизитах некоторых таблиц. Любая арифметика с NULL даёт NULL, а сравнение с NULL всегда ложно — поэтому необработанные NULL ломают и вычисления, и отборы.
Функция ЕСТЬNULL(Выражение, ЗначениеПоУмолчанию) подставляет замену, если выражение равно NULL. Классический пример — остатки с левым соединением:
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Товары.Ссылка = Остатки.Номенклатура
Не путайте NULL и пустую ссылку: это разные значения. Если реквизит в базе хранит пустую ссылку на справочник, ЕСТЬNULL её не заменит — потребуется либо сравнение с ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка), либо конструкция ВЫБОР с явной проверкой. Перед написанием условия полезно выполнить тестовый запрос и посмотреть, что фактически лежит в поле.
Как проверить результат запроса с функциями
Совпадают с итогом по исходной таблице при ручной сверке на малом периоде
Суммы кратно завышены — вероятно, соединение размножает строки до группировки
Нет пустых ячеек там, где применён ЕСТЬNULL
NULL в числовых колонках — функция забыта или применена не к тому полю
Найдены все ожидаемые записи, включая разный регистр букв
Часть записей пропала — проверьте регистр и лишние пробелы в данных
Функции в виртуальных таблицах и параметрах
Отдельный класс — функции, встроенные в механизм виртуальных таблиц регистров. Параметры виртуальных таблиц (период, условие, группировка) сами по себе работают как функции обработки: например, параметр условия в таблице ОстаткиИОбороты фильтрует данные на уровне СУБД до того, как начнётся соединение с другими таблицами. Поэтому переносить отборы в параметры виртуальной таблицы почти всегда выгоднее, чем фильтровать в ГДЕ после выборки.
Конструкция ЗНАЧЕНИЕ(Перечисление.СтавкиНДС.НДС20) тоже относится к функциям языка запросов: она позволяет обратиться к предопределённому значению перечисления, элемента справочника или пустой ссылке без параметра. Это удобно для жёстко заданных отборов, но снижает гибкость — если значение может меняться, правильнее передать его параметром.
Для табличных частей документов в запросе доступно обращение через точку как к вложенной таблице, и функции применяются к её полям так же, как к полям обычных таблиц. Например, СУММА по строкам табличной части с группировкой по ссылке даст итог документа без обращения к регистрам.
Где выполнять вычисления: запрос или код
Подходит для агрегации, фильтрации и простых преобразований. Выполняется на СУБД, быстрее на больших объёмах, но набор функций ограничен
Подходит для сложной строковой логики, алгоритмов с ветвлениями и вызовов прикладных функций. Медленнее на больших выборках, требует перебора строк
Подходит для отчётов, где выражение должен менять пользователь. Требует знакомства с языком выражений СКД, не применимо в произвольных запросах кода
Производительность и безопасные приёмы
Любая функция, применённая к полю в условии ГДЕ или в соединении, как правило, блокирует использование индекса по этому полю. Запрос вида ГДЕ НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) = &Дата на большой таблице будет сканировать её целиком. Правильная замена — вычислить границы периода параметрами и написать условие диапазона: ГДЕ Дата МЕЖДУ &НачалоДня И &КонецДня.
Второй риск — функции в соединениях. Соединение по условию с ПОДСТРОКА или ВЫРАЗИТЬ заставляет СУБД вычислять выражение для каждой комбинации строк. Если такое соединение необходимо, сначала выберите обе таблицы во временные с уже вычисленными полями, проиндексируйте их и соединяйте временные таблицы — это штатный приём оптимизации в 1С.
Перед выкладкой запроса в рабочую базу проверяйте его на копии или в консоли запросов на реальном объёме данных: запрос, отрабатывающий за секунду на тестовой базе с сотней документов, на рабочей базе с миллионами записей может выполняться минутами и блокировать таблицы.
Частые вопросы по функциям в запросах 1С
Можно ли использовать функции встроенного языка (Формат, СтрЗаменить) в запросе?
Нет. Язык запросов — самостоятельный язык со своим ограниченным набором функций, и функции встроенного языка 1С в нём недоступны. Если нужна такая обработка, выполняйте её в коде после получения результата запроса или используйте вычисляемые поля СКД для отчётов.
Почему СУММА вернула NULL вместо нуля?
Если в группируемой выборке нет ни одной строки или все значения поля равны NULL, агрегатная функция возвращает NULL. Оберните её в ЕСТЬNULL: ЕСТЬNULL(СУММА(Поле), 0) — тогда при отсутствии данных получите ноль.
Как сравнить только даты без времени?
Используйте НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) с обеих сторон сравнения либо передавайте в запрос границы дня параметрами и сравнивайте через МЕЖДУ. Второй вариант предпочтительнее на больших таблицах, так как не мешает использованию индекса по полю даты.
Чем отличается КОЛИЧЕСТВО() от КОЛИЧЕСТВО(Поле)?
КОЛИЧЕСТВО() считает все строки группы, а КОЛИЧЕСТВО(Поле) — только строки, где поле не равно NULL. Для подсчёта уникальных значений используйте КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле).
Можно ли вызвать свою функцию из общего модуля в запросе?
В обычном запросе — нет. Такая возможность есть только в языке выражений СКД через вычисляемые поля и функции общих модулей с соответствующими настройками, но это отдельный механизм, работающий только внутри системы компоновки данных.
Почему запрос с ВЫРАЗИТЬ в соединении работает медленно?
Приведение типа вычисляется для каждой строки при соединении, и СУБД не может использовать индекс. Вынесите обе таблицы во временные с уже приведёнными полями, проиндексируйте временные таблицы по полю соединения и соединяйте их — это стандартный способ ускорить такой запрос.
Что важно запомнить
Агрегатные функции требуют группировки, скалярные — нет. NULL обрабатывайте через ЕСТЬNULL, типы приводите через ВЫРАЗИТЬ, даты формируйте через ДАТАВРЕМЯ и параметры. Функции в условиях и соединениях отключают индексы — на больших таблицах выносите вычисления во временные таблицы и проверяйте запрос на копии базы.