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

Программист 1С v7.7 Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Проанализируем распространенную проблему: если во встроенном языке запросов обратиться к периодическому реквизиту через точку (например, Справочник.СКЛ_Инвентарь.Владелец.Подразделение), запрос возвращает последнее значение на дату окончания выборки или рабочую дату. Если в истории изменений реквизита была создана запись с незаполненным значением (к примеру, при проведении кадрового документа должность изменилась, а подразделение не было заполнено), встроенный запрос вернет пустоту. Рассмотрим подробнее, почему так происходит и какими способами можно получить корректные данные.

Причина поведения запроса и структуры данных

Выясним причину такого поведения платформы. Встроенный язык запросов 1С 7.7 не умеет самостоятельно перебирать историю назад до первого непустого значения. Запрос выполняет жесткий срез значений на дату среза. Если на эту дату последняя запись в истории реквизита пустая, запрос добросовестно вернет пустое значение.

Существует несколько проверенных подходов для решения этой задачи в зависимости от архитектуры вашего решения и требований к быстродействию.

Способ 1. Указание точного периода выборки в тексте запроса

Если вам требуется получить срез периодических реквизитов на определенную дату (например, дату документа или актуальную рабочую дату отчета), необходимо явно задать период в тексте запроса с помощью конструкции Период с ... по ....

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


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

В этом случае платформа сформирует срез периодических реквизитов именно на переменную ДатаАктуальности, что исключит влияние более поздних пустых записей, если они были внесены будущим числом.

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

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

Разберем по шагам данный алгоритм:

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

ТЗ = СоздатьОбъект("ТаблицаЗначений");
Запрос.Выгрузить(ТЗ);

ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    ТЗ.Подразделение = ТЗ.Владелец.Подразделение.Получить(ТекущаяДата());
КонецЦикла;

Обратите внимание: для обхода строк таблицы значений в 1С 7.7 используется метод ПолучитьСтроку(), а не несуществующий ПолучитьСледующий.

Способ 3. Использование системного объекта «Периодический» для поиска последнего непустого значения

Если в истории изменений действительно содержатся пустые записи и вам необходимо найти именно последнее заполненное значение, стандартный метод Получить() вернет пустую строку. В этом случае воспользуемся системным объектом Периодический, который позволяет перебрать историю реквизита в цикле назад.

Рассмотрим пример функции, возвращающей последнее непустое значение:


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

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

Способ 4. Использование прямых SQL-запросов (1С++)

Для высоконагруженных баз и больших объемов данных вызовы функций встроенного языка в цикле могут существенно снизить производительность. В таких ситуациях эффективным решением являются прямые SQL-запросы к таблице _1SCONST через внешние компоненты.

При прямом обращении к базе данных отбор последнего непустого значения строится следующим образом:

  1. Устанавливается фильтр по идентификатору объекта (OBJID) и идентификатору реквизита (ID).
  2. Накладывается условие среза даты: DATE <= :ВыбДата.
  3. Исключаются пустые значения поля VALUE.
  4. Выполняется сортировка по убыванию даты и времени: ORDER BY DATE DESC, TIME DESC, DOCID DESC с получением первой записи (TOP 1).

Способ 5. Исправление данных и алгоритмов проведения документов

Проанализируем первопричину возникновения проблемы. Появление пустых срезов в периодических реквизитах чаще всего вызвано ошибкой в модулях документов, изменяющих кадровые данные или параметры объектов.

Чтобы избежать подобных ситуаций в будущем, рекомендуется:

  1. Скорректировать код проведения: если реквизит в документе не выбран пользователем, документ не должен безусловно перезаписывать периодический реквизит справочника пустым значением.
  2. Очистить историю: интерактивно через кнопку «История» (клавиша F5 в форме элемента справочника) либо служебной обработкой удалить ошибочные пустые записи на даты кадровых перемещений.
← На главную