В процессе разработки на платформе 1С:Предприятие часто возникают задачи, когда необходимо получить агрегированные данные (сумму) по табличной части документа, но при этом исключить из расчета определенную запись. Типичный пример — необходимость вычесть значение самой первой строки из общего итога. Это может быть связано с особенностями бизнес-логики, когда первая строка содержит аванс, корректировочное значение или заголовочную информацию, которую не следует суммировать с остальными данными.
В этой статье мы подробно разберем, как реализовать подобную логику непосредственно в языке запросов 1С, рассмотрим различные подходы — от классических фильтров до современных методов с использованием оконных функций, и проанализируем возможные «подводные камни».
Самый простой и производительный способ — это отсечение ненужной строки еще до того, как данные попадут в механизм агрегации. Если нам нужно просуммировать все строки, кроме первой, мы можем использовать системный реквизит табличной части НомерСтроки.
Рассмотрим этот способ на примере. Допустим, нам нужно получить сумму неустойки по документу ЛК_Претензия, исключив первую строку:
ВЫБРАТЬ
СУММА(ЛК_Претензия.Неустойка) КАК Неустойка
ИЗ
Документ.ЛК_Претензия.ОсновныеДанные КАК ЛК_Претензия
ГДЕ
ЛК_Претензия.Ссылка = &Ссылка
И ЛК_Претензия.НомерСтроки <> 1
Преимущества данного метода:
Важное ограничение: Если ваш запрос выбирает данные сразу по нескольким документам (как в исходном вопросе на форуме), условие ЛК_Претензия.НомерСтроки <> 1 исключит первую строку из каждого документа, попавшего в выборку. Если ваша задача — исключить только одну-единственную «самую первую» строку во всем наборе данных, этот метод потребует доработки через временные таблицы.
Если нам необходимо в одном запросе получить и полную сумму, и сумму без первой строки, или если логика исключения более сложная, мы можем использовать оператор ВЫБОР внутри агрегатной функции СУММА. Это позволяет гибко управлять тем, какие значения участвуют в расчете.
Разберем вариант, предложенный участниками обсуждения:
ВЫБРАТЬ
СУММА(ВЫБОР
КОГДА ЛК_Претензия.НомерСтроки = 1 ТОГДА 0
ИНАЧЕ ЛК_Претензия.Неустойка
КОНЕЦ) КАК НеустойкаБезПервойСтроки
ИЗ
Документ.ЛК_Претензия.ОсновныеДанные КАК ЛК_Претензия
ГДЕ
ЛК_Претензия.Ссылка.Контрагент = &Контрагент
В данном примере мы анализируем каждую строку: если это первая строка, мы прибавляем к итогу 0, во всех остальных случаях — значение поля Неустойка. Проанализируем также альтернативный вариант записи — вычитание:
ВЫБРАТЬ
СУММА(ЛК_Претензия.Неустойка) -
СУММА(ВЫБОР
КОГДА ЛК_Претензия.НомерСтроки = 1 ТОГДА ЛК_Претензия.Неустойка
ИНАЧЕ 0
КОНЕЦ) КАК ИтоговаяСумма
ИЗ
Документ.ЛК_Претензия.ОсновныеДанные КАК ЛК_Претензия
Здесь мы сначала считаем общую сумму, а затем вычитаем из нее сумму, состоящую только из значения первой строки. Этот подход полезен, если в итоговой выборке вам нужны оба показателя одновременно.
При выполнении арифметических операций в запросах крайне важно помнить о значениях NULL. Если в результате фильтрации или отсутствия данных в табличной части запрос вернет NULL, любая попытка вычитания из этого значения приведет к тому, что весь результат станет NULL.
Рекомендуем всегда использовать функцию ЕСТЬNULL для обеспечения стабильности расчетов:
ВЫБРАТЬ
ЕСТЬNULL(СУММА(ЛК_Претензия.Неустойка), 0) -
ЕСТЬNULL(СУММА(ВЫБОР
КОГДА ЛК_Претензия.НомерСтроки = 1 ТОГДА ЛК_Претензия.Неустойка
ИНАЧЕ 0
КОНЕЦ), 0) КАК Результат
Если вы работаете на современной платформе (начиная с версии 8.3.21), вы можете использовать мощный инструмент — оконные функции. Это особенно полезно, когда «первая строка» определяется не физическим порядком в табличной части (НомерСтроки), а, например, самой ранней датой или минимальной ценой внутри группы строк.
Рассмотрим, как пронумеровать строки динамически и исключить первую:
ВЫБРАТЬ
ВТ_Данные.Неустойка КАК Неустойка
ИЗ (
ВЫБРАТЬ
ЛК_Претензия.Неустойка КАК Неустойка,
НОМЕР_СТРОКИ() OVER (ПОРЯДОК ПО ЛК_Претензия.Дата) КАК ВнутреннийНомер
ИЗ
Документ.ЛК_Претензия.ОсновныеДанные КАК ЛК_Претензия
) КАК ВТ_Данные
ГДЕ
ВТ_Данные.ВнутреннийНомер > 1
Этот метод позволяет гибко определять, какая именно строка будет считаться «первой», независимо от того, как они были введены пользователем в интерфейсе.
Проанализируем ситуацию, какой метод выбрать в зависимости от ваших целей:
ГДЕ). Это самый быстрый способ.ВЫБОР).НомерСтроки = 1 будет у каждого документа. Если нужно исключить только одну строку из всего массива документов, используйте вложенные запросы для определения глобального идентификатора этой строки.Резюме: Вычитание или исключение значения поля в запросе 1С чаще всего реализуется через фильтрацию системного реквизита НомерСтроки. Однако всегда стоит учитывать контекст задачи: количество документов в выборке, возможные NULL в данных и необходимость специфической сортировки. Правильное использование ЕСТЬNULL и понимание работы агрегатных функций позволит вам избежать типичных ошибок при расчете итогов.