Функции языка запросов 1С: ЕСТЬNULL, ВЫБОР, РАЗНОСТЬДАТ
Функции языка запросов закрывают NULL, режут даты на периоды, считают разность дат и строят условные значения. На собесе спрашивают про ЕСТЬNULL и ЕСТЬ NULL, про РАЗНОСТЬДАТ на границе суток и про то, почему ГОД(Дата) в условии тормозит. Результаты сверены на PostgreSQL.
// Так спрашивают: «Чем ЕСТЬNULL отличается от ЕСТЬ NULL?» «Сколько вернёт РАЗНОСТЬДАТ между 23:00 и 01:00 следующего дня в днях?» «Что вернёт СУММА по пустой выборке?» «Почему ГОД(Дата) = 2026 в условии плохо?»
ЕСТЬNULL и ЕСТЬ NULL
ЕСТЬNULL с двумя аргументами заменяет NULL значением: ЕСТЬNULL(Остатки.Количество, 0). Проверка на NULL в условии пишется раздельно: Поле ЕСТЬ NULL. Равенство Поле = NULL не срабатывает никогда, потому что любое сравнение с NULL не истинно.
Агрегат по пустому набору без группировки возвращает одну строку с NULL, а не ноль. Продажи за день, когда продаж не было:
Если такую сумму сложить в коде с числом, расчёт упадёт на ошибке преобразования NULL. ЕСТЬNULL в самом запросе решает это раз и навсегда.
ВЫБРАТЬ
СУММА(Р.СуммаДокумента) КАК Сумма,
ЕСТЬNULL(СУММА(Р.СуммаДокумента), 0) КАК СуммаИлиНоль
ИЗ
Документ.Реализация КАК Р
ГДЕ
Р.Дата МЕЖДУ &НачалоДня И &КонецДняДаты
НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) приводит дату к началу месяца, по ней группируют продажи по месяцам. ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, 7) сдвигает дату. ДАТАВРЕМЯ(2026, 10, 1) принимает только числа-константы, из полей дату им не собрать.
РАЗНОСТЬДАТ(&Начало, &Конец, ДЕНЬ) считает, сколько границ суток пересекли, а не сколько полных суток прошло. Поэтому 23:00 и 01:00 следующего дня дают 1, хотя прошло два часа:
Для просрочки «больше трёх суток» по времени такая разность врёт, там считают в секундах или часах. Для «сколько календарных дней между датами документов» она как раз подходит.
Функция над полем в условии ломает индекс: ГОД(Р.Дата) = 2026 заставит СУБД (система управления базами данных) посчитать год у каждой строки. Тот же отбор диапазоном Р.Дата МЕЖДУ &Начало И &Конец идёт по индексу по дате.
ВЫБРАТЬ
РАЗНОСТЬДАТ(&Вечер, &Ночь, ДЕНЬ) КАК Дней,
РАЗНОСТЬДАТ(&Вечер, &Ночь, ЧАС) КАК Часов
// &Вечер = 14.10.2026 23:00, &Ночь = 15.10.2026 01:00ВЫБОР и ПРЕДСТАВЛЕНИЕ
ВЫБОР строит значение по условию, это аналог CASE из SQL. Ветки разных типов дают составной тип колонки, поэтому ветки приводят к одному типу. Разложим суммы продаж по размеру:
ВЫБОР проверяет ветки сверху вниз и берёт первую подходящую, поэтому 1 200 попала в «крупную», а не в «среднюю». ПРЕДСТАВЛЕНИЕ(Р.Контрагент) получает текст ссылки прямо в запросе, без отдельного обращения к базе на каждую строку при выводе.
ВЫБРАТЬ
Р.Номер,
ВЫБОР
КОГДА Р.СуммаДокумента >= 1000 ТОГДА "крупная"
КОГДА Р.СуммаДокумента >= 500 ТОГДА "средняя"
ИНАЧЕ "мелкая"
КОНЕЦ КАК Размер
ИЗ
Документ.Реализация КАК Р
УПОРЯДОЧИТЬ ПО
Р.НомерКак отвечать: «Почему отчёт падает на пустом периоде, хотя на заполненном работает?»
Скорее всего в запросе агрегат без группировки, например СУММА по продажам. На пустом наборе он возвращает не ноль, а одну строку с NULL, и код дальше пытается сложить NULL с числом. Лечится ЕСТЬNULL(СУММА(...), 0) прямо в запросе. Заодно проверю левые соединения: у строк без пары там тоже NULL.
Ответ находит причину по симптому «падает только на пустом» и лечит её в запросе, а не проверками в коде. Упоминание левых соединений показывает системный взгляд на NULL.
На чём валят
- −Ждут ноль от СУММА по пустому набору. Без группировки вернётся одна строка с NULL. Оборачивают ЕСТЬNULL.
- −Проверяют
Поле = NULL. Сравнение с NULL не истинно. ПишутПоле ЕСТЬ NULL. - −Пишут
ГОД(Дата) = 2026в условии. Функция над полем ломает индекс. Отбор диапазоном дат. - −Считают просрочку в сутках через РАЗНОСТЬДАТ(…, ДЕНЬ). Функция считает границы суток: 23:00 и 01:00 дают 1. Просрочку по времени считают в секундах или часах.
Проверь себя
Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.
- Как получить в запросе начало месяца для даты документа?A)
НАЧАЛОПЕРИОДА(Д.Дата, МЕСЯЦ)B)ДАТАВРЕМЯ(ГОД(Д.Дата), МЕСЯЦ(Д.Дата), 1)C)ОКРУГЛИТЬ(Д.Дата, МЕСЯЦ)D)НачалоМесяца(Д.Дата)показать ответ и разбор
+A)`НАЧАЛОПЕРИОДА(Д.Дата, МЕСЯЦ)`// разбор: НАЧАЛОПЕРИОДА(Дата, Период) приводит дату к началу периода: ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД и других. Так группируют продажи по месяцам. ДАТАВРЕМЯ в языке запросов принимает только константы, а НачалоМесяца — функция встроенного языка, в запросе её нет.
- Что вернёт
РАЗНОСТЬДАТ(&Н, &К, ДЕНЬ)для &Н = 01.03 23:00 и &К = 02.03 01:00?A)Ошибку: разные датыB)0C)2D)1показать ответ и разбор
+D)1// разбор: РАЗНОСТЬДАТ с периодом ДЕНЬ считает, сколько границ суток пересечено между датами, а не полные 24 часа. Между 1 марта 23:00 и 2 марта 01:00 одна граница — получится 1, хотя прошло два часа. Для точного интервала берут СЕКУНДА и делят.
- Что делает
ВЫБОР КОГДА Т.Сумма > 1000 ТОГДА "крупный" ИНАЧЕ "мелкий" КОНЕЦ?A)Группирует строки по сумме в две группыB)Отбирает строки с суммой больше 1000C)Сортирует строки по сумме, крупные первымиD)Вычисляет значение по условию для строкипоказать ответ и разбор
+D)Вычисляет значение по условию для строки// разбор: ВЫБОР — условное выражение, аналог CASE: возвращает значение первой подходящей ветки, иначе ветку ИНАЧЕ. Без ИНАЧЕ для неподходящих строк вернётся NULL. Строки он не отбирает, это делает ГДЕ.
- Как в запросе оставить только движения, где регистратор — документ «Реализация»?A)
ТИП(Р.Регистратор) = Документ.РеализацияB)Р.Регистратор = "Реализация"C)Р.Регистратор ССЫЛКА Документ.РеализацияD)Р.Регистратор.ВидДокумента = "Реализация"показать ответ и разбор
+C)`Р.Регистратор ССЫЛКА Документ.Реализация`// разбор: Оператор ССЫЛКА проверяет, что значение составного поля — ссылка указанного типа. Эквивалентно ТИПЗНАЧЕНИЯ(Р.Регистратор) = ТИП(Документ.Реализация). Сравнение со строкой и обращение к несуществующему полю ВидДокумента не работают.
- Зачем в запросе выбирать
ПРЕДСТАВЛЕНИЕ(Т.Контрагент), если в коде можно вывести саму ссылку?A)Чтобы получить ИНН контрагента в том же полеB)Без запроса за каждой ссылкойC)Чтобы обойти права доступа к справочникуD)Ссылку нельзя вывести в отчётпоказать ответ и разбор
+B)Без запроса за каждой ссылкой// разбор: При выводе ссылки платформа получает её представление отдельным обращением к базе, и на тысячах строк это тысячи мелких запросов. ПРЕДСТАВЛЕНИЕ в запросе получает текст сразу, одним соединением. Для ссылочных полей в СКД платформа делает это сама.
дальше
Теорию прочитал. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, бесплатная часть практики — одна сессия дня в сутки.