Как вычислить количество строк в табличной части документа через запрос в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача: получить данные из шапки документа вместе с общим количеством строк в его табличной части. Казалось бы, простая арифметическая операция, но в языке запросов 1С она требует понимания механизмов агрегации и работы с реляционными таблицами. В этой статье мы подробно разберем все способы решения этой задачи, проанализируем их эффективность и выясним, какой метод лучше использовать в различных ситуациях.

Способ 1: Использование группировки и агрегатной функции КОЛИЧЕСТВО

Это самый стандартный и часто используемый метод. Поскольку табличная часть документа хранится в отдельной физической таблице базы данных, для подсчета строк нам необходимо обратиться именно к ней. Разберем типичную ситуацию на примере документа ОприходованиеТоваров. Нам нужно получить номер, дату, сумму документа и количество позиций в табличной части Товары.

Рассмотрим пример запроса, который можно быстро подготовить через управляемую консоль запросов:


ВЫБРАТЬ
    ОприходованиеТоваровТовары.Ссылка.Номер КАК Номер,
    ОприходованиеТоваровТовары.Ссылка.Дата КАК Дата,
    ОприходованиеТоваровТовары.Ссылка.СуммаДокумента КАК Сумма,
    КОЛИЧЕСТВО(ОприходованиеТоваровТовары.НомерСтроки) КАК КоличествоСтрок
ИЗ
    Документ.ОприходованиеТоваров.Товары КАК ОприходованиеТоваровТовары
ГДЕ
    ОприходованиеТоваровТовары.Ссылка.Дата > &Дата
СГРУППИРОВАТЬ ПО
    ОприходованиеТоваровТовары.Ссылка.Номер,
    ОприходованиеТоваровТовары.Ссылка.Дата,
    ОприходованиеТоваровТовары.Ссылка.СуммаДокумента

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

Способ 2: Использование МАКСИМУМ(НомерСтроки)

Проанализируем ситуацию: в платформе 1С поле НомерСтроки в табличной части автоматически инкрементируется и всегда содержит порядковый номер записи. Если в вашей конфигурации не предусмотрено специфическое удаление строк с нарушением нумерации (что редкость для типовых механизмов), то максимальное значение этого поля и будет являться количеством строк.

Посмотрим на пример такого запроса:


ВЫБРАТЬ
    ОприходованиеТоваровТовары.Ссылка КАК Ссылка,
    МАКСИМУМ(ОприходованиеТоваровТовары.НомерСтроки) КАК ВсегоСтрок
ИЗ
    Документ.ОприходованиеТоваров.Товары КАК ОприходованиеТоваровТовары
СГРУППИРОВАТЬ ПО
    ОприходованиеТоваровТовары.Ссылка

Этот метод считается более производительным в некоторых случаях, так как поиск максимального значения по индексированному полю может выполняться быстрее, чем полный подсчет записей. Однако помните, что если в документе была удалена строка без пересчета номеров остальных строк (например, при прямом SQL-запросе, что крайне не рекомендуется), данные могут быть ошибочными.

Способ 3: Оптимизация через временные таблицы

Выясним причину, по которой сложные запросы с подсчетом строк могут тормозить. Если вы соединяете документ с несколькими табличными частями (например, Товары и СпецОснастка) и в каждой пытаетесь вычислить количество строк через группировку в основном запросе, вы получите эффект "декартова произведения". Строки начнут множиться, и итоговые числа будут в разы больше реальных.

Рассмотрим, как правильно решить задачу с помощью временных таблиц (для их отладки подойдет консоль запросов УФ):

  1. Сначала создаем временную таблицу, где вычисляем количество строк для нужных документов.
  2. Затем соединяем основную таблицу документа с этой временной таблицей.

// Шаг 1: Подсчет количества во временную таблицу
ВЫБРАТЬ
    Товары.Ссылка КАК Ссылка,
    КОЛИЧЕСТВО(Товары.НомерСтроки) КАК КолВоСтрок
ПОМЕСТИТЬ ВТ_КоличествоСтрок
ИЗ
    Документ.ОприходованиеТоваров.Товары КАК Товары
ГДЕ
    Товары.Ссылка.Дата > &Дата
СГРУППИРОВАТЬ ПО
    Товары.Ссылка;

// Шаг 2: Получение основных данных
ВЫБРАТЬ
    Док.Номер,
    Док.Дата,
    Док.СуммаДокумента,
    ЕСТЬNULL(ВТ.КолВоСтрок, 0) КАК КоличествоСтрок
ИЗ
    Документ.ОприходованиеТоваров КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_КоличествоСтрок КАК ВТ
    ПО Док.Ссылка = ВТ.Ссылка
ГДЕ
    Док.Дата > &Дата

Этот подход гарантирует точность данных. Использование ЛЕВОЕ СОЕДИНЕНИЕ и функции ЕСТЬNULL позволяет корректно отобразить "0" для документов, у которых табличная часть пуста.

Способ 4: Получение вложенной таблицы (nested tables)

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

Посмотрим на пример запроса:


ВЫБРАТЬ
    ОприходованиеТоваров.Номер,
    ОприходованиеТоваров.Дата,
    ОприходованиеТоваров.Товары.(КОЛИЧЕСТВО(НомерСтроки) КАК КолВо) КАК КоличествоВложенное
ИЗ
    Документ.ОприходованиеТоваров КАК ОприходованиеТоваров

Результат: В поле КоличествоВложенное придет не число, а объект типа РезультатЗапроса. Чтобы извлечь из него количество, вам придется в коде 1С при обходе выборки использовать метод Выборка.КоличествоВложенное.Выбрать().Количество(). Это удобно для иерархического вывода данных, но крайне неудобно для простых отчетов или списков.

Рекомендации по выбору метода

Проанализируем ситуацию и выберем оптимальный путь:

Помните, что использование КОЛИЧЕСТВО(*) в запросе 1С к табличной части допустимо, но КОЛИЧЕСТВО(НомерСтроки) считается более "красивым" стилем программирования, так как вы явно указываете на поле, которое гарантированно заполнено в каждой строке.

← На главную