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

Программист 1С v7.7 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

Часто при разработке или доработке отчетов в 1С 7.7, таких как «Состояние заказа» в конфигурации «Торговля и Склад», возникает задача: вывести данные не в алфавитном порядке наименований, а в строгом соответствии с порядком строк в исходном документе. Стандартный язык запросов 1С 7.7 по умолчанию группирует и сортирует данные по измерениям, например, по номенклатуре. Попытка добавить группировку по переменной НомерСтроки обычно приводит к тому, что возвращается ноль. Рассмотрим подробнее, почему так происходит, и разберем по шагам несколько рабочих способов решения этой задачи.

Почему стандартный запрос не видит номер строки?

Проанализируем архитектуру хранения данных в платформе 1С 7.7. Данные регистров физически делятся на две таблицы: таблицу движений (RA) и таблицу итогов (RG). Системная переменная НомерСтроки отсутствует в таблицах итогов (RG). Математический аппарат системы сворачивает и агрегирует остатки исключительно по измерениям регистра (в нашем случае — по Заказу и Номенклатуре).

Даже если в модуле проведения документа использовать метод ПривязыватьНомерСтроки(), номер строки запишется только в таблицу движений (RA). Поэтому функции встроенного языка запросов, оперирующие остатками (например, КонОст), физически не могут выполнить группировку или сортировку по номеру строки — этих данных для остатков просто не существует в базе. Выясним, как обойти это ограничение.

Решение 1: Выгрузка в Таблицу Значений (ТЗ) и ручная сортировка

Это классический метод, который часто применяется разработчиками 1С 7.7. Суть заключается в том, чтобы получить данные запросом, выгрузить их в Таблицу Значений, а затем программно связать с номерами строк документа.

Разберем алгоритм по шагам:

  1. Выполняем стандартный запрос, получающий остатки и движения, и выгружаем результат в Таблицу Значений.
  2. Добавляем в полученную ТЗ новую колонку, например, НомерСтрокиДока.
  3. Открываем цикл по табличной части документа-заказа.
  4. Для каждой строки документа ищем соответствующую номенклатуру в нашей ТЗ. Если находим — записываем в колонку НомерСтрокиДока текущий номер строки документа.
  5. Сортируем Таблицу Значений по новой колонке НомерСтрокиДока.
  6. Обходим отсортированную ТЗ и выводим строки в печатную форму отчета.

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

Решение 2: Использование метода позиционирования Запрос.Получить()

Вместо ресурсоемкой работы с Таблицами Значений и ручной сортировки, в 1С 7.7 можно применить метод прямого позиционирования в выборке запроса. Посмотрим на пример реализации данного подхода.

Алгоритм действий:

  1. Исходный запрос выполняется как обычно, без попыток внедрить туда сортировку по строкам. Оставляем только штатную команду Группировка Номенклатура Без Групп;.
  2. Вместо перебора выборки запроса (через Пока Запрос.Группировка(1) = 1), мы открываем цикл по табличной части самого документа-заказа:
    
    ВыбДокумент.ВыбратьСтроки();
    Пока ВыбДокумент.ПолучитьСтроку() = 1 Цикл
        // внутри цикла позиционируемся
    КонецЦикла;
    
  3. Внутри этого цикла используем метод позиционирования на результатах запроса по значению из текущей строки документа:
    
    Если Запрос.Получить(ВыбДокумент.Номенклатура) = 1 Тогда
        // Вывод секции отчета с данными запроса
    КонецЕсли;
    

Поскольку перебор идет непосредственно по табличной части документа, строки выводятся в отчет в строгом соответствии с их оригинальной нумерацией и порядком.

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

Решение 3: Прямые SQL-запросы (1С++ / SQLite)

Если проект позволяет использовать внешние компоненты, стоит рассмотреть переход на прямые запросы. Это наиболее технологичный путь, который полностью снимает ограничения встроенного «черного» запроса 1С 7.7.

В архитектуре баз данных 1С 7.7 табличная часть документа хранится в физической таблице базы данных (с префиксом DT...), которая всегда содержит системное поле LINENO_ — это и есть номер строки. При использовании компоненты 1С++ мы пишем прямой SELECT, в котором связываем таблицу табличной части документа с таблицами движений и остатков регистра через LEFT JOIN.

В конце такого SQL-запроса достаточно указать конструкцию ORDER BY DT.LINENO_. Система управления базами данных (СУБД) самостоятельно выполнит объединение и вернет готовый, агрегированный результат, идеально отсортированный по номерам строк исходного документа. Это работает мгновенно и не требует дополнительных циклов и обработок в коде 1С.

← На главную