Как писать вычисления, условия и приведение типов в языке запросов 1С
Содержание
Выражение в запросе 1С — это всё, что стоит на месте поля: вычисление Количество * Цена, условие ВЫБОР КОГДА … КОНЕЦ, функция НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) или приведение типа ВЫРАЗИТЬ(Поле КАК Справочник.Номенклатура). Синтаксис одинаков в секциях ВЫБРАТЬ, ГДЕ, СГРУППИРОВАТЬ ПО, ИМЕЮЩИЕ и УПОРЯДОЧИТЬ ПО. Результату выражения почти всегда дают имя через КАК, иначе платформа назовёт колонку сама («Поле1»).
Вычислить можно двумя способами: прямо в запросе или потом в коде, обходя выборку. Запрос выигрывает, когда результат нужен для отбора, группировки или сортировки: СУБД сделает это быстрее цикла. Код удобнее, когда нужна сложная логика с вызовом функций общих модулей — язык запросов их не вызывает.
Операнды и арифметика: из чего собирается выражение
Операндом может быть поле таблицы, параметр &Параметр, литерал или результат другой функции.
📌 Литералы, которые встречаются чаще всего:
- числа —
100,0.2(разделитель — точка); - строки —
"Москва"в двойных кавычках; - даты —
ДАТАВРЕМЯ(2025, 1, 1)или с временемДАТАВРЕМЯ(2025, 1, 1, 23, 59, 59); - булево —
ИСТИНА,ЛОЖЬ; NULLиНЕОПРЕДЕЛЕНО;- предопределённые значения —
ЗНАЧЕНИЕ(Перечисление.ВидыОпераций.Продажа),ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка).
Арифметических операций четыре: +, -, *, /. Умножение и деление выполняются раньше сложения и вычитания, скобки меняют порядок как в школе.
ВЫБРАТЬ
Товары.Номенклатура КАК Номенклатура,
Товары.Количество * Товары.Цена КАК Сумма,
Товары.Количество * Товары.Цена * 20 / 120 КАК НДСВключенный,
(Товары.Цена - Товары.Себестоимость) * Товары.Количество КАК Наценка
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Товары
ГДЕ
Товары.Ссылка = &Документ
Проверим на числах: 3 шт. по 1 200 руб. дают 3 600 руб., НДС внутри — 3 600 × 20 / 120 = 600 руб.
Любая арифметика с NULL даёт NULL. Если поле пришло из левого соединения и записи нет, Количество * Цена вернёт пустоту, а не ноль. Оборачивайте такие поля в ЕСТЬNULL(Поле, 0).
Имена таблиц и полей в примерах взяты из типовой конфигурации. В вашей базе сверяйте их через конструктор запроса: он показывает реальные реквизиты.
Строковые выражения: склейка, ПОДСТРОКА и поиск по шаблону
Строки склеивают плюсом: Контрагенты.Наименование + " (" + Контрагенты.ИНН + ")". Оба операнда должны быть строками.
ПОДСТРОКА
ПОДСТРОКА(Строка, Начало, Длина) вырезает кусок. Нумерация символов с единицы: ПОДСТРОКА("Накладная", 1, 4) вернёт «Накл».
У функции есть второе, практическое применение. Строки неограниченной длины (например, реквизит Комментарий) нельзя сравнивать, группировать и упорядочивать. ПОДСТРОКА(Комментарий, 1, 200) превращает такое поле в строку фиксированной длины, и с ним уже можно работать.
ПОДОБНО
Оператор ПОДОБНО проверяет строку по шаблону.
🔹 Спецсимволы шаблона:
%— любое количество любых символов;_— ровно один любой символ;[абв]— один символ из перечисленных;[^абв]— один символ, кроме перечисленных.
ГДЕ
Номенклатура.Артикул ПОДОБНО "АБ-___"
И Номенклатура.Наименование ПОДОБНО "%кабель%"
Чтобы искать сам символ процента или подчёркивания, укажите экранирующий знак через СПЕЦСИМВОЛ:
ГДЕ
Номенклатура.Наименование ПОДОБНО "%50~%%" СПЕЦСИМВОЛ "~"
Шаблон найдёт «Скидка 50%», «50% предоплата» и подобные строки.
Функции для строк в новых платформах
В платформе 8.3.20 и новее в язык запросов добавили привычные строковые функции: ДЛИНАСТРОКИ, СТРНАЙТИ, СТРЗАМЕНИТЬ, ВРЕГ, НРЕГ, ЛЕВ, ПРАВ, СОКРЛ, СОКРП, СОКРЛП. Работают они так же, как одноимённые функции встроенного языка.
💡 Если база работает в режиме совместимости с более старой версией, эти функции в запросе вызовут синтаксическую ошибку. Режим совместимости виден в свойствах корня конфигурации в Конфигураторе.
Условия в запросе: ВЫБОР КОГДА и логические операторы
Конструкция ВЫБОР
Аналог Если … ИначеЕсли … КонецЕсли в запросе выглядит так:
ВЫБРАТЬ
Остатки.Номенклатура,
ВЫБОР
КОГДА Остатки.КоличествоОстаток <= 0 ТОГДА "Нет в наличии"
КОГДА Остатки.КоличествоОстаток < 10 ТОГДА "Заканчивается"
ИНАЧЕ "В наличии"
КОНЕЦ КАК Статус
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата) КАК Остатки
Условия проверяются сверху вниз, срабатывает первое истинное. Без ИНАЧЕ результат будет NULL, если ни одна ветка не подошла.
ВЫБОР годится не только в ВЫБРАТЬ. Его ставят внутрь агрегатной функции, в условие соединения и в УПОРЯДОЧИТЬ ПО — например, чтобы вывести наверх определённый склад.
Логические операторы
| Оператор | Пример | Что проверяет |
|---|---|---|
И, ИЛИ, НЕ | Сумма > 0 И НЕ ПометкаУдаления | Комбинация условий |
МЕЖДУ … И … | Дата МЕЖДУ &Начало И &Конец | Диапазон включительно |
В (…) | Склад В (&СписокСкладов) | Вхождение в список или подзапрос |
В ИЕРАРХИИ | Номенклатура В ИЕРАРХИИ (&Группа) | Элемент и все вложенные группы |
ЕСТЬ NULL | Цены.Цена ЕСТЬ NULL | Значение отсутствует |
ССЫЛКА | Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг | Тип ссылки |
Сравнение Поле = NULL никогда не бывает истинным. Для проверки пустоты из соединения есть только ЕСТЬ NULL и НЕ … ЕСТЬ NULL.
Даты в запросе: периоды, сдвиги и разница
Работа с датой в запросе держится на четырёх функциях и наборе «извлекателей».
| Функция | Пример | Результат |
|---|---|---|
НАЧАЛОПЕРИОДА | НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) | 01.03.2025 00:00:00 для 17.03.2025 |
КОНЕЦПЕРИОДА | КОНЕЦПЕРИОДА(Дата, ДЕНЬ) | 17.03.2025 23:59:59 |
ДОБАВИТЬКДАТЕ | ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, 30) | Дата плюс 30 дней |
РАЗНОСТЬДАТ | РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) | Дата2 минус Дата1 в днях |
Основные периоды для первых трёх функций: ГОД, КВАРТАЛ, МЕСЯЦ, ДЕКАДА, НЕДЕЛЯ, ДЕНЬ, ЧАС, МИНУТА, у ДОБАВИТЬКДАТЕ есть ещё СЕКУНДА. В РАЗНОСТЬДАТ доступны СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД.
Пример: сколько дней прошло от отгрузки до даты отчёта.
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
РАЗНОСТЬДАТ(Реализация.Дата, &ДатаОтчета, ДЕНЬ) КАК ДнейПрошло
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен
Отгрузка 01.03, отчёт на 31.03 — в колонке будет 30.
Извлечь часть даты помогают ГОД(), КВАРТАЛ(), МЕСЯЦ(), ДЕНЬ(), ДЕНЬГОДА(), НЕДЕЛЯ(), ДЕНЬНЕДЕЛИ(), ЧАС(), МИНУТА(), СЕКУНДА(). ДЕНЬНЕДЕЛИ возвращает 1 для понедельника и 7 для воскресенья.
💡 Группировать продажи по месяцам удобнее через НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ), а не через МЕСЯЦ(Дата). Номер месяца склеит март 2024 и март 2025 в одну строку, а начало периода — нет.
Как выразить тип в запросе 1С: ВЫРАЗИТЬ, ССЫЛКА и ТИПЗНАЧЕНИЯ
Синтаксис ВЫРАЗИТЬ … КАК
ВЫРАЗИТЬ(Выражение КАК Тип) приводит значение к указанному типу. Типы бывают примитивные и ссылочные:
ВЫРАЗИТЬ(Комментарий КАК СТРОКА(150))— обрезает строку неограниченной длины до 150 символов;ВЫРАЗИТЬ(Сумма / Количество КАК ЧИСЛО(15, 2))— оставляет два знака после запятой;ВЫРАЗИТЬ(Субконто1 КАК Справочник.Контрагенты)— сужает составной тип до одного.
Если значение не приводится к типу, вместо ошибки вернётся NULL. Это удобно: ВЫРАЗИТЬ(Субконто1 КАК Справочник.Контрагенты) даст ссылку на контрагента, а для строк, где в субконто лежит договор или статья затрат, — NULL.
Главный приём: ВЫРАЗИТЬ для полей составного типа
Поле Регистратор у регистра может ссылаться на десятки видов документов. Запись Регистратор.Номер заставляет платформу соединить таблицу регистра со всеми этими документами. Запрос раздувается и тормозит.
Решение — сначала отобрать нужный тип, потом выразить поле:
ВЫБРАТЬ
Движения.Регистратор КАК Документ,
ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент
ИЗ
РегистрНакопления.Продажи КАК Движения
ГДЕ
Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
Теперь соединение идёт с одной таблицей документов. На регистрах с миллионами записей разница в скорости бывает в разы. Тот же приём применяют к субконто, к реквизиту Объект в регистрах сведений и к любому полю с несколькими типами.
ТИПЗНАЧЕНИЯ и ТИП
ССЫЛКА проверяет тип ссылки, а для сравнения произвольных типов есть пара функций:
ГДЕ
ТИПЗНАЧЕНИЯ(Хозрасчетный.Субконто1) = ТИП(Справочник.Номенклатура)
ТИП() принимает и примитивы: ТИП(ЧИСЛО), ТИП(СТРОКА), ТИП(ДАТА).
ПРЕДСТАВЛЕНИЕ и ПРЕДСТАВЛЕНИЕССЫЛКИ
ПРЕДСТАВЛЕНИЕ(Поле) возвращает текстовое представление значения. Для ссылок платформа добавляет такое поле при выводе в отчёт сама. Используйте функцию в итоговой выборке, а не в условиях ГДЕ: сравнивать по представлению медленно и ненадёжно.
Агрегатные функции и выражения при группировке
Функций шесть:
| Функция | Что считает |
|---|---|
СУММА(Поле) | Сумму, NULL пропускает |
КОЛИЧЕСТВО(Поле) | Число строк, где поле не NULL |
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Поле) | Число уникальных значений |
КОЛИЧЕСТВО(*) | Все строки |
МАКСИМУМ, МИНИМУМ | Наибольшее и наименьшее |
СРЕДНЕЕ(Поле) | Среднее по непустым значениям |
Внутрь агрегата можно поставить любое выражение. Так считают условные суммы в одной строке:
ВЫБРАТЬ
Продажи.Контрагент КАК Контрагент,
СУММА(Продажи.Сумма) КАК Всего,
СУММА(ВЫБОР
КОГДА Продажи.Период >= &НачалоМесяца ТОГДА Продажи.Сумма
ИНАЧЕ 0
КОНЕЦ) КАК ЗаТекущийМесяц,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Продажи.Регистратор) КАК ЧислоДокументов
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Период МЕЖДУ &НачалоГода И &КонецПериода
СГРУППИРОВАТЬ ПО
Продажи.Контрагент
ИМЕЮЩИЕ
СУММА(Продажи.Сумма) > 100000
🔸 Правила, которые проверяет платформа:
- каждое поле в
ВЫБРАТЬлибо стоит под агрегатной функцией, либо перечислено вСГРУППИРОВАТЬ ПО; - группировать можно по выражению:
СГРУППИРОВАТЬ ПО НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)— в выборке тогда пишут то же выражение; - условие на исходные строки ставят в
ГДЕ, условие на итог группы — вИМЕЮЩИЕ.
Средняя цена через СРЕДНЕЕ(Цена) считает среднее арифметическое строк, без учёта объёма. Средневзвешенная цена — это СУММА(Сумма) / СУММА(Количество), и её нужно защитить от деления на ноль (ниже).
Выражения в СКД: что работает иначе
Текст запроса в схеме компоновки данных пишется на том же языке, со всеми функциями из разделов выше. Отличаются поля, которые задают на вкладках схемы.
🔹 Где в СКД встречаются выражения:
- вычисляемые поля — формула от полей набора, например
Сумма - Себестоимость; - ресурсы — выражение итога, например
Сумма(Сумма)илиСумма(Сумма) / Сумма(Количество); - условное оформление и отборы — условия по полям.
Язык выражений СКД похож на язык запросов, но не совпадает с ним. В нём можно вызывать экспортные функции общих модулей, есть функция ВычислитьВыражение для расчётов по группировкам. Вычисляемые поля считаются уже после выполнения запроса, поэтому отбор по ним не ускоряет выборку из базы.
💡 Если поле нужно для отбора или группировки на больших объёмах, рассчитайте его в тексте запроса набора данных, а не вычисляемым полем.
Частые ошибки в выражениях и медленные конструкции
Ошибки, которые останавливают запрос
- ❌
Поле не входит в группу— поле есть вВЫБРАТЬ, но его нет вСГРУППИРОВАТЬ ПОи оно не под агрегатом. Добавьте поле в группировку или оберните вМАКСИМУМ. - ❌ Деление на ноль. СУБД прерывает запрос. Делитель проверяют заранее:
ВЫБОР
КОГДА СУММА(Продажи.Количество) = 0 ТОГДА 0
ИНАЧЕ СУММА(Продажи.Сумма) / СУММА(Продажи.Количество)
КОНЕЦ КАК СредняяЦена
- ❌ Сравнение строки неограниченной длины. Платформа не даёт сравнивать и группировать такие поля — приведите их через
ВЫРАЗИТЬ(… КАК СТРОКА(N))илиПОДСТРОКА. - ❌
NULLвместо числа. Итог по левому соединению пустой, потому что одна из колонокNULL. ЛечитсяЕСТЬNULL.
Выражения, которые убивают скорость
| Конструкция | Почему медленно | Как переписать |
|---|---|---|
НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) = &День в ГДЕ | Функция над полем мешает СУБД использовать индекс | Дата МЕЖДУ &НачалоДня И &КонецДня |
Наименование ПОДОБНО "%текст%" | Ведущий % требует просмотра всей таблицы | Шаблон с началом строки "текст%", если подходит по смыслу |
Регистратор.Дата у составного поля | Соединение со всеми типами документов | ССЫЛКА в условии + ВЫРАЗИТЬ |
Отбор в ГДЕ по виртуальной таблице | Таблица сначала собирается целиком | Условие в параметрах таблицы: Остатки(&Дата, Склад = &Склад) |
Длинная цепочка ИЛИ по разным полям | Индекс часто не используется | ОБЪЕДИНИТЬ ВСЕ двух запросов или временная таблица |
Тяжёлое выражение, которое нужно в нескольких местах, выгоднее посчитать один раз во временной таблице (ПОМЕСТИТЬ ВТ_Данные) и дальше обращаться к готовому полю.
Частые вопросы
Можно ли вызвать функцию общего модуля в тексте запроса?
Чем ЕСТЬNULL отличается от ЕСТЬ NULL?
ЕСТЬNULL(Поле, 0) — функция замены: возвращает второй аргумент, если первый пустой. Поле ЕСТЬ NULL — логическое условие, возвращает ИСТИНА или ЛОЖЬ.Как в запросе округлить число до копеек?
ВЫРАЗИТЬ(Сумма * 1.2 КАК ЧИСЛО(15, 2)). Первое число — общая длина, второе — знаки после запятой.Как подставить в запрос значение перечисления?
ЗНАЧЕНИЕ(Перечисление.ИмяПеречисления.ИмяЗначения) прямо в тексте или параметром. Для пустой ссылки — ЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка).Где проверить выражение, не запуская отчёт?
ОК.