Как вывести данные из разных видов документов в одну строку запроса 1С 7.7

Программист 1С v7.7
← На главную

При разработке отчетов в системе 1С:Предприятие 7.7 программисты часто сталкиваются с ограничением стандартного механизма запросов (так называемого «черного запроса»). Проблема заключается в том, что при попытке выбрать данные из разных видов документов по общему реквизиту (например, ИСН или Контрагент), система выводит результаты в разные строки, даже если значения группировочного поля совпадают. Разберем подробно, как заставить систему объединить эти данные в одну строку таблицы.

Причина возникновения проблемы

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

Способ 1. Использование иерархических группировок

Проанализируем самый простой и правильный с точки зрения логики 1С 7.7 подход. Вместо того чтобы пытаться получить все данные «плоским» списком сразу, мы используем вложенность группировок. Основная идея заключается в том, чтобы сделать ИСН верхней группировкой, а документы — вложенной.

Рассмотрим пример построения текста запроса:


ТекстЗапроса = "//{{ЗАПРОС()
|Период с ДатаНачала по ДатаОкончания;
|ОбрабатыватьДокументы все;
|ИСН = Документ.ЗаявкаПокупателя.ИСН, Документ.РемонтОборудования.ИСН;
|Док = Документ.ЗаявкаПокупателя.ТекущийДокумент, Документ.РемонтОборудования.ТекущийДокумент;
|Группировка ИСН без групп;
|Группировка Док;
|Условие(ИСН = ВыбИСН);
|";

При обходе результатов такого запроса мы будем действовать следующим образом: на уровне группировки ИСН мы открываем строку таблицы, а затем внутри цикла по вложенной группировке Док собираем данные из всех найденных документов в переменные и выводим их в ту же самую строку.

Посмотрим на пример кода обработки результатов:


Пока Запрос.Группировка("ИСН") = 1 Цикл
    // Инициализируем переменные для данных из разных документов
    ДатаРемонта = "";
    НомерРемонта = "";
    ДатаЗаявки = "";
    НомерЗаявки = "";
    
    Пока Запрос.Группировка("Док") = 1 Цикл
        ТекДок = Запрос.Док;
        Если ТекДок.Вид() = "РемонтОборудования" Тогда
            ДатаРемонта = ТекДок.ДатаДок;
            НомерРемонта = ТекДок.НомерДок;
        ИначеЕсли ТекДок.Вид() = "ЗаявкаПокупателя" Тогда
            ДатаЗаявки = ТекДок.ДатаДок;
            НомерЗаявки = ТекДок.НомерДок;
        КонецЕсли;
    КонецЦикла;
    
    // Теперь у нас есть данные из обоих документов (если они существуют)
    // и мы можем вывести их в ОДНУ строку секции отчета
    Таб.ВывестиСекцию("Строка");
КонецЦикла;

Способ 2. Постобработка в Таблице Значений (ТЗ)

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

Разберем алгоритм «ручной» свертки:

  1. Выполняем запрос и выгружаем результат в ТаблицаЗначений.
  2. Создаем новую ТаблицаЗначений с нужной структурой колонок (где для каждого вида документа свои колонки).
  3. Перебираем исходную таблицу. Для каждой строки ищем в новой таблице строку с таким же ИСН (используя метод НайтиЗначение).
  4. Если строка найдена — дополняем её данными. Если нет — добавляем новую строку.

Проанализируем пример кода для объединения строк в ТЗ:


ТЗ_Результат.НоваяКолонка("ИСН");
ТЗ_Результат.НоваяКолонка("Док1");
ТЗ_Результат.НоваяКолонка("Док2");

ТЗ_Запроса.ВыбратьСтроки();
Пока ТЗ_Запроса.ПолучитьСтроку() = 1 Цикл
    НомерСтр = 0;
    Если ТЗ_Результат.НайтиЗначение(ТЗ_Запроса.ИСН, НомерСтр, "ИСН") = 1 Тогда
        ТЗ_Результат.ПолучитьСтрокуПоНомеру(НомерСтр);
    Иначе
        ТЗ_Результат.НоваяСтрока();
        ТЗ_Результат.ИСН = ТЗ_Запроса.ИСН;
    КонецЕсли;
    
    Если ТЗ_Запроса.Док.Вид() = "РемонтОборудования" Тогда
        ТЗ_Результат.Док1 = ТЗ_Запроса.Док;
    Иначе
        ТЗ_Результат.Док2 = ТЗ_Запроса.Док;
    КонецЕсли;
КонецЦикла;

Способ 3. Агрегатные функции в тексте запроса

Малоизвестный, но эффективный прием в 1С 7.7 — использование функций Максимум или Минимум для «поднятия» значений на уровень вышестоящей группировки. Если мы заранее знаем, что для одного ИСН может существовать не более одного документа каждого вида, мы можем прописать это прямо в тексте запроса.

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


ТекстЗапроса = "
|ИСН = Документ.ЗаявкаПокупателя.ИСН, Документ.РемонтОборудования.ИСН;
|ДатаЗаявки = Документ.ЗаявкаПокупателя.ДатаДок;
|ДатаРемонта = Документ.РемонтОборудования.ДатаДок;
|Функция МаксДатаЗаявки = Максимум(ДатаЗаявки);
|Функция МаксДатаРемонта = Максимум(ДатаРемонта);
|Группировка ИСН;
|";

В этом случае при обходе группировки ИСН значения Запрос.МаксДатаЗаявки и Запрос.МаксДатаРемонта будут доступны одновременно в одной и той же итерации цикла, даже если эти даты получены из разных физических записей базы данных.

Способ 4. Использование внешних компонент (SQL)

Для профессиональной разработки под 1С 7.7 часто используются прямые SQL-запросы через внешние компоненты, такие как 1C++. Это позволяет использовать всю мощь языка SQL, включая соединение таблиц LEFT JOIN.

В SQL-запросе мы можем просто соединить две таблицы документов по полю ИСН:


SELECT 
    Doc1.IDDOC as [ДокРемонт $Документ.РемонтОборудования],
    Doc2.IDDOC as [ДокЗаявка $Документ.ЗаявкаПокупателя],
    ISNULL(Doc1.SP123, Doc2.SP456) as ИСН
FROM [ЖурналДокументов] as Journal
LEFT JOIN [Документ_РемонтОборудования] as Doc1 ON ...
LEFT JOIN [Документ_ЗаявкаПокупателя] as Doc2 ON ...
WHERE ...

Такой подход работает значительно быстрее штатных средств 1С, особенно если база данных работает под управлением MS SQL Server. Использование конструкции GROUP BY на стороне сервера позволяет сразу получить готовую таблицу, где одна строка соответствует одному ИСН со всеми привязанными документами.

Рекомендации по оптимизации

При работе с запросами по нескольким видам документов важно учитывать следующие моменты:

Мы рассмотрели основные способы решения задачи. Выбор конкретного метода зависит от объема данных и ваших требований к производительности системы. Для небольших отчетов идеально подходит Способ 1, а для высоконагруженных систем лучше смотреть в сторону Прямых SQL-запросов.

← На главную