При разработке отчетов и обработок в 1С часто возникает необходимость получить простой список товаров или услуг из документов за определенный период и по конкретному контрагенту. Однако начинающие разработчики сталкиваются с ситуацией, когда запрос возвращает результат с вложенными таблицами для каждого документа, а не единую линейную (сквозную) таблицу.
Разберем, почему возникает такая ситуация и как правильно составлять запросы к табличным частям документов в платформе 1С:Предприятие.
Рассмотрим исходный запрос, в котором поля табличной части выбираются через скобки из таблицы шапки документа:
ВЫБРАТЬ
ПередачаТоваров.Товары.(
Номенклатура КАК Номенклатура,
Количество КАК Количество
) КАК Товары
ИЗ
Документ.ПередачаТоваров КАК ПередачаТоваров
ГДЕ
ПередачаТоваров.Дата МЕЖДУ &ДатН И &ДатК
И ПередачаТоваров.Контрагент = &Контр
Синтаксис обращения к табличной части через скобки Документ.ТабличнаяЧасть.(Поле1, Поле2) предназначен для получения иерархических структур с выборкой типа РезультатЗапросаСВложеннымиТаблицами. Такой подход используется, когда требуется обходить документы по очереди, а внутри каждого документа обходить его строки. Для получения единого сквозного списка всех строк из всех документов данный синтаксис не подходит.
Чтобы получить плоскую (линейную) таблицу, необходимо указывать в качестве источника данных в секции ИЗ непосредственно табличную часть документа — Документ.ПередачаТоваров.Товары.
Посмотрим на базовый пример такого запроса:
ВЫБРАТЬ
ПередачаТоваровТовары.Номенклатура КАК Номенклатура,
ПередачаТоваровТовары.Количество КАК Количество
ИЗ
Документ.ПередачаТоваров.Товары КАК ПередачаТоваровТовары
ГДЕ
ПередачаТоваровТовары.Ссылка.Дата МЕЖДУ &ДатН И &ДатК
И ПередачаТоваровТовары.Ссылка.Контрагент = &Контр
В данном случае обращение к реквизитам шапки (полям Дата и Контрагент) выполняется через реквизит Ссылка, который присутствует в каждой строке табличной части.
Часто в практических задачах требуется не просто вывести список всех строк, а сгруппировать одинаковые позиции номенклатуры и посчитать их общее количество. Проанализируем вариант с использованием агрегатных функций и группировки:
ВЫБРАТЬ
ПередачаТоваровТовары.Номенклатура КАК Номенклатура,
СУММА(ПередачаТоваровТовары.Количество) КАК Количество
ИЗ
Документ.ПередачаТоваров.Товары КАК ПередачаТоваровТовары
ГДЕ
ПередачаТоваровТовары.Ссылка.Дата МЕЖДУ &ДатН И &ДатК
И ПередачаТоваровТовары.Ссылка.Контрагент = &Контр
СГРУППИРОВАТЬ ПО
ПередачаТоваровТовары.Номенклатура
Конструкция СГРУППИРОВАТЬ ПО сводит повторяющиеся позиции номенклатуры из разных документов в одну строку, а функция СУММА складывает их количество.
При выполнении прямого запроса к табличной части выборка по умолчанию охватывает абсолютно все строки — в том числе из непроведенных документов или документов, помеченных на удаление. Если бизнес-логика требует учитывать только проведенные документы, необходимо добавить условие проверки статуса документа.
Рассмотрим итоговый корректный запрос с фильтрацией по состоянию документа:
ВЫБРАТЬ
ПередачаТоваровТовары.Номенклатура КАК Номенклатура,
СУММА(ПередачаТоваровТовары.Количество) КАК Количество
ИЗ
Документ.ПередачаТоваров.Товары КАК ПередачаТоваровТовары
ГДЕ
ПередачаТоваровТовары.Ссылка.Дата МЕЖДУ &ДатН И &ДатК
И ПередачаТоваровТовары.Ссылка.Контрагент = &Контр
И ПередачаТоваровТовары.Ссылка.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
ПередачаТоваровТовары.Номенклатура
При работе с большими объемами данных важно учитывать особенности генерации SQL-кода платформой 1С:
ПередачаТоваровТовары.Ссылка.Контрагент) приводит к созданию неявного LEFT JOIN с таблицей документов на уровне СУБД. Это абсолютно нормально для небольших и средних выборок.Ссылка, а затем соединять её с табличной частью.