К статье
Практический материал

Разработка и Конфигурация · 13 мин

Как использовать функции в запросе 1С

Как использовать функции в запросе 1С: агрегатные функции, работа со строками и датами, ПОДСТРОКА, РАЗНОСТЬДАТ, ВЫРАЗИТЬ, примеры кода и типичные ошибки.

Язык запросов 1С — это не только выборка полей из таблиц. Встроенные функции позволяют прямо в тексте запроса суммировать обороты, обрезать строки, вычислять разницу между датами, приводить типы и подставлять значения вместо NULL. Грамотное использование функций сокращает объём построчной обработки результата в коде и снижает нагрузку на сервер, потому что вычисления выполняются на уровне СУБД.

Главное, что нужно понять сразу: функции в запросе делятся на два класса. Агрегатные функции — СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ — сворачивают группу строк в одно значение. Функции обработки значений — ПОДСТРОКА, ДАТАВРЕМЯ, РАЗНОСТЬДАТ, ВЫРАЗИТЬ, ЕСТЬNULL и другие — применяются к каждой строке отдельно и не требуют группировки. Смешивать эти классы без понимания их поведения — самая частая причина ошибок «Неверные параметры агрегатной функции» и неожиданных результатов.

Ниже разобраны оба класса с конкретными примерами синтаксиса, ограничениями платформы и типичными ошибками, которые встречаются у разработчиков при переносе логики из кода в запрос.

Агрегатные функции: СУММА, КОЛИЧЕСТВО, МАКСИМУМ и группировка

Агрегатные функции вычисляют одно значение по набору строк. Если в запросе есть хотя бы одна агрегатная функция, все остальные поля в списке выборки обязаны либо входить в предложение СГРУППИРОВАТЬ ПО, либо тоже быть обёрнуты в агрегат. Иначе конструктор запроса выдаст ошибку ещё на этапе проверки текста.

Типичный пример — сумма продаж по контрагентам:

ВЫБРАТЬ

Продажи.Контрагент КАК Контрагент,

СУММА(Продажи.СуммаОборот) КАК СуммаПродаж,

КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Продажи.Регистратор) КАК ЧислоДокументов

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи

СГРУППИРОВАТЬ ПО

Продажи.Контрагент

Обратите внимание на конструкцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле): она считает уникальные значения, а не все строки. Без ключевого слова РАЗЛИЧНЫЕ вы получите количество строк в группе, что при детальных таблицах даст завышенные цифры. Это одна из самых коварных ошибок — запрос выполняется без предупреждений, но числа неверные.

Функции МИНИМУМ и МАКСИМУМ работают не только с числами, но и с датами и строками — удобно, когда нужно найти первую или последнюю дату документа по клиенту. СРЕДНЕЕ считает среднее арифметическое по непустым значениям: строки, где поле равно NULL, в расчёт не берутся, и это нужно учитывать при интерпретации результата.

Типичные ошибки с агрегатными функциями
01
Поле в списке выборки не входит ни в СГРУППИРОВАТЬ ПО, ни в агрегатную функцию — запрос не проходит проверку или возвращает ошибку выполнения
02
КОЛИЧЕСТВО без РАЗЛИЧНЫЕ — считаются строки, а не уникальные документы, итоги завышены
03
Ожидание, что СУММА по пустой выборке вернёт 0 — на самом деле вернётся NULL, нужен ЕСТЬNULL
04
Группировка по полю составного типа с последующим сравнением — дублирование строк из-за разных типов значений

Функции работы со строками: ПОДСТРОКА и её ограничения

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

ВЫБРАТЬ

ПОДСТРОКА(Номенклатура.Артикул, 1, 3) КАК ПрефиксАртикула,

Номенклатура.Ссылка КАК Товар

ИЗ

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

ГДЕ

ПОДСТРОКА(Номенклатура.Артикул, 1, 2) = "AB"

Для поиска по вхождению подстроки вместо функций используется оператор ПОДОБНО с шаблоном: ГДЕ Наименование ПОДОБНО "%кабель%". Символ процента заменяет любую последовательность символов, подчёркивание — один символ. Спецсимволы в шаблоне экранируются через конструкцию СПЕЦСИМВОЛ.

Практический вывод: если задача требует сложной строковой логики — разбора ФИО, нормализации телефонов, замены символов — её лучше выполнять в коде после выборки или на этапе записи данных, а не пытаться эмулировать в запросе вложенными ПОДСТРОКА. Такие конструкции плохо читаются и не оптимизируются СУБД.

Функции работы с датами: ДАТАВРЕМЯ, РАЗНОСТЬДАТ, НАЧАЛОПЕРИОДА

Для формирования константной даты в запросе используется функция ДАТАВРЕМЯ(Год, Месяц, День, Час, Минута, Секунда). Часы, минуты и секунды можно опустить — тогда получится начало дня. Пустая дата записывается как ДАТАВРЕМЯ(1, 1, 1). Литералы даты в кавычках запрос не принимает — попытка сравнить поле со строкой вида «01.01.2026» даст ошибку несоответствия типов.

Функция РАЗНОСТЬДАТ(Дата1, Дата2, Единица) возвращает разницу между двумя датами в заданных единицах: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Типичный сценарий — расчёт просрочки по документам:

ВЫБРАТЬ

Заказы.Ссылка КАК Заказ,

РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки

ИЗ

Документ.ЗаказКлиента КАК Заказы

ГДЕ

РАЗНОСТЬДАТ(Заказы.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) > 3

Функции НАЧАЛОПЕРИОДА(Дата, Период) и КОНЕЦПЕРИОДА(Дата, Период) приводят дату к границе указанного интервала — дня, недели, месяца, квартала, года. Это удобно для группировки оборотов по месяцам без виртуальных таблиц: группируете по НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) и получаете помесячную аналитику. Учтите, что КОНЕЦПЕРИОДА для типа Дата с точностью до секунды возвращает последнюю секунду периода, что важно при сравнениях на «меньше или равно».

Функция ДОБАВИТЬКДАТЕ(Дата, Единица, Количество) сдвигает дату на заданное число единиц — например, ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1) вернёт ту же дату месяц назад. Это избавляет от вычисления границ периода в коде и передачи лишних параметров.

Как посчитать просрочку по документам
  1. 1
    Передайте в запрос параметр &ТекущаяДата — функции «текущая дата» в языке запросов нет, её подставляют из кода
  2. 2
    В списке выборки напишите РАЗНОСТЬДАТ(ДатаДокумента, &ТекущаяДата, ДЕНЬ) с понятным псевдонимом
  3. 3
    Добавьте условие ГДЕ на ту же конструкцию, чтобы отсечь непросроченные документы
  4. 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, типы приводите через ВЫРАЗИТЬ, даты формируйте через ДАТАВРЕМЯ и параметры. Функции в условиях и соединениях отключают индексы — на больших таблицах выносите вычисления во временные таблицы и проверяйте запрос на копии базы.