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

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

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

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

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

Рассмотрим стандартный запрос, который вызывает затруднения:


//{{ЗАПРОС(ПоследниеПоступления)
|Период с НачДок по ДатаКон;
|Товар = Регистр.ОстаткиТоваров.Товар;
|Док = Регистр.ОстаткиТоваров.ТекущийДокумент;
|ОстатокТовара = Регистр.ОстаткиТоваров.ОстатокТовара;
// Попытка обратиться к цене из ТЧ здесь не сработает
|Функция ПриходКол = Приход(ОстатокТовара);
|Группировка Товар без групп;
|Группировка Док;
//}}ЗАПРОС

В данном случае переменная Док после выполнения запроса будет содержать объект типа «Документ». Чтобы получить цену, нам пришлось бы внутри цикла обхода результатов запроса открывать каждый документ, искать в нем нужную строку с товаром и извлекать значение. Рассмотрим, как сделать это оптимальнее.

Решение 1: Постобработка через выгрузку табличной части

Если количество документов в отчете не исчисляется тысячами, можно воспользоваться методом постобработки. Однако важно делать это правильно, чтобы не «повесить» систему постоянным обращением к диску. Вместо медленного перебора строк документа через ВыбратьСтроки(), мы применим метод ВыгрузитьТабличнуюЧасть().

Разберем алгоритм действий:

  1. Выполняем основной запрос по регистру.
  2. При обходе группировки по документам получаем объект документа.
  3. Выгружаем его строки в ТаблицуЗначений.
  4. Находим нужную строку по товару и получаем цену.

Пример кода для реализации этого подхода:


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

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

Решение 2: Использование прямых SQL-запросов (1С++)

Для высоконагруженных систем это единственный «правильный» путь. Использование внешней компоненты 1С++ позволяет написать прямой SQL-запрос к таблицам базы данных. В SQL мы можем легко объединить (JOIN) таблицу движений регистра (например, RAXXXX) с таблицей строк документа (DTXXXX).

Проанализируем преимущества этого метода:

Схематично SQL-запрос будет выглядеть так (где $НомерСтроки — это реквизит, связывающий регистр со строкой, если он добавлен):


SELECT 
    Reg.Товар as [Товар $Справочник.Товары],
    DocRows.Цена as Цена
FROM 
    [Регистр.ОстаткиТоваров] as Reg
INNER JOIN 
    [ДокументСтроки.Приходная] as DocRows ON Reg.ТекущийДокумент = DocRows.IDDoc
WHERE 
    Reg.Товар = DocRows.Товар

Решение 3: Изменение архитектуры (Добавление реквизита в регистр)

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

Рассмотрим шаги по реализации без риска разрушения последовательности:

  1. Добавьте в структуру регистра ОстаткиТоваров новый реквизит Цена.
  2. Измените модуль проведения документа, чтобы при записи движений значение цены транслировалось в регистр.
  3. Для старых данных (с 2009 года, как в примере автора) напишите обработку, которая переберет движения и запишет туда цену. Важно: используйте метод Записать() в режиме редактирования записей регистра без выполнения Провести(), чтобы не затронуть последовательность и другие регистры.

После этого ваш запрос станет максимально простым и быстрым:


|Товар = Регистр.ОстаткиТоваров.Товар;
|Цена = Регистр.ОстаткиТоваров.Цена; // Теперь это поле доступно напрямую!
|Функция ПриходКол = Приход(ОстатокТовара);

Решение 4: Расчет через суммовые регистры

Если в вашей конфигурации сохранились другие регистры (например, Продажи или ПартииТоваров), проверьте, нет ли там суммовых показателей. В 1С 7.7 цена часто вычисляется как РесурсСумма / РесурсКоличество. Если регистр партий ведется, то цена поступления всегда доступна в нем. Достаточно изменить объект запроса с ОстаткиТоваров на ПартииТоваров, и вы получите доступ к стоимостным показателям без обращения к табличным частям документов.

Заключение

Мы проанализировали ситуацию и выяснили, что стандартный запрос 1С 7.7 ограничен в работе с табличными частями. Выбор решения зависит от ваших технических возможностей: для разовых отчетов подойдет выгрузка ТЧ в таблицу значений, для производительных систем — прямые SQL-запросы, а для долгосрочного удобства — корректировка структуры регистров. Помните, что архитектура «Торговли» 2002 года выпуска часто требует оптимизации под современные объемы данных.

← На главную