Часто при разработке или доработке отчетов в 1С 7.7, таких как «Состояние заказа» в конфигурации «Торговля и Склад», возникает задача: вывести данные не в алфавитном порядке наименований, а в строгом соответствии с порядком строк в исходном документе. Стандартный язык запросов 1С 7.7 по умолчанию группирует и сортирует данные по измерениям, например, по номенклатуре. Попытка добавить группировку по переменной НомерСтроки обычно приводит к тому, что возвращается ноль. Рассмотрим подробнее, почему так происходит, и разберем по шагам несколько рабочих способов решения этой задачи.
Проанализируем архитектуру хранения данных в платформе 1С 7.7. Данные регистров физически делятся на две таблицы: таблицу движений (RA) и таблицу итогов (RG). Системная переменная НомерСтроки отсутствует в таблицах итогов (RG). Математический аппарат системы сворачивает и агрегирует остатки исключительно по измерениям регистра (в нашем случае — по Заказу и Номенклатуре).
Даже если в модуле проведения документа использовать метод ПривязыватьНомерСтроки(), номер строки запишется только в таблицу движений (RA). Поэтому функции встроенного языка запросов, оперирующие остатками (например, КонОст), физически не могут выполнить группировку или сортировку по номеру строки — этих данных для остатков просто не существует в базе. Выясним, как обойти это ограничение.
Это классический метод, который часто применяется разработчиками 1С 7.7. Суть заключается в том, чтобы получить данные запросом, выгрузить их в Таблицу Значений, а затем программно связать с номерами строк документа.
Разберем алгоритм по шагам:
НомерСтрокиДока.НомерСтрокиДока текущий номер строки документа.НомерСтрокиДока.Этот алгоритм работает достаточно надежно и скорость выполнения для небольших документов (в несколько десятков строк) остается приемлемой. Однако, если строк тысячи, вложенные циклы могут замедлить формирование отчета.
Вместо ресурсоемкой работы с Таблицами Значений и ручной сортировки, в 1С 7.7 можно применить метод прямого позиционирования в выборке запроса. Посмотрим на пример реализации данного подхода.
Алгоритм действий:
Группировка Номенклатура Без Групп;.Пока Запрос.Группировка(1) = 1), мы открываем цикл по табличной части самого документа-заказа:
ВыбДокумент.ВыбратьСтроки();
Пока ВыбДокумент.ПолучитьСтроку() = 1 Цикл
// внутри цикла позиционируемся
КонецЦикла;
Если Запрос.Получить(ВыбДокумент.Номенклатура) = 1 Тогда
// Вывод секции отчета с данными запроса
КонецЕсли;
Поскольку перебор идет непосредственно по табличной части документа, строки выводятся в отчет в строгом соответствии с их оригинальной нумерацией и порядком.
Важный нюанс: обработка дублей строк.
При использовании любого из вышеописанных методов нужно учитывать поведение дублей. Если в документе одна и та же номенклатура встречается в нескольких строках, стандартный запрос 1С предварительно свернет её итоги и остатки в одну общую запись. При последовательном обходе строк документа (или при поиске в ТЗ) эти свернутые общие остатки будут получены для каждой дублирующейся строки заново. В таких ситуациях потребуется либо выводить итог только при первом вхождении номенклатуры, либо математически распределять полученный остаток (например, ОстатокЗаказа) пропорционально количеству в конкретной строке документа перед выводом на печать.
Если проект позволяет использовать внешние компоненты, стоит рассмотреть переход на прямые запросы. Это наиболее технологичный путь, который полностью снимает ограничения встроенного «черного» запроса 1С 7.7.
В архитектуре баз данных 1С 7.7 табличная часть документа хранится в физической таблице базы данных (с префиксом DT...), которая всегда содержит системное поле LINENO_ — это и есть номер строки. При использовании компоненты 1С++ мы пишем прямой SELECT, в котором связываем таблицу табличной части документа с таблицами движений и остатков регистра через LEFT JOIN.
В конце такого SQL-запроса достаточно указать конструкцию ORDER BY DT.LINENO_. Система управления базами данных (СУБД) самостоятельно выполнит объединение и вернет готовый, агрегированный результат, идеально отсортированный по номерам строк исходного документа. Это работает мгновенно и не требует дополнительных циклов и обработок в коде 1С.