Как в запросе 1С исключить исходный документ, если на его основании введено исправление?

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом Управленческий учет IT и автоматизация бизнеса
← На главную

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

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

Постановка задачи и логика поиска исправлений

В типовых конфигурациях 1С связь между исправляющим и исправляемым документом обычно реализуется через реквизит ИсправленныйДокумент или ПерерассчитываемыйДокумент. Если мы делаем запрос к табличной части документа, например, ОплатаПраздничныхИВыходныхДнейОрганизаций, нам нужно оставить только те строки, ссылка на которые не фигурирует в поле ПерерассчитываемыйДокумент у других проведенных документов этого же типа.

Проанализируем ситуацию: если документ «А» был исправлен документом «Б», то в документе «Б» реквизит ПерерассчитываемыйДокумент будет содержать ссылку на документ «А». Следовательно, в нашем отчете документ «А» должен исчезнуть, а данные должны подтянуться только из документа «Б».

Шаг 1: Формирование списка «черных» ссылок (исправленных документов)

Первым делом нам необходимо собрать все ссылки на документы, которые были кем-то исправлены. Эти ссылки мы поместим во временную таблицу. Рассмотрим, как это сделать правильно, чтобы избежать дублирования и учесть только проведенные документы.


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Док.ПерерассчитываемыйДокумент КАК СсылкаДляИсключения
ПОМЕСТИТЬ ВТ_ИсправленныеДокументы
ИЗ
    Документ.ОплатаПраздничныхИВыходныхДнейОрганизаций КАК Док
ГДЕ
    Док.Проведен = ИСТИНА
    И Док.ПерерассчитываемыйДокумент <> ЗНАЧЕНИЕ(Документ.ОплатаПраздничныхИВыходныхДнейОрганизаций.ПустаяСсылка)
ИНДЕКСИРОВАТЬ ПО
    СсылкаДляИсключения
;

Обратим внимание на важные моменты в этом коде:

Шаг 2: Получение основных данных с исключением

Теперь рассмотрим, как использовать полученную временную таблицу. Одной из распространенных ошибок является использование перекрестного соединения (выбор через запятую), как было показано в обсуждении на форуме. Если временная таблица окажется пустой (нет ни одного исправления), то весь запрос вернет пустой результат. Чтобы этого избежать, мы будем использовать оператор ГДЕ НЕ ... В (...) или ЛЕВОЕ СОЕДИНЕНИЕ.

Проанализируем вариант с использованием условия НЕ В. Это наиболее простой и читаемый способ для начинающего разработчика:


ВЫБРАТЬ
    Начисления.Сотрудник,
    Начисления.ДатаВыхода,
    Начисления.Ссылка,
    Начисления.ВидРасчета
ИЗ
    Документ.ОплатаПраздничныхИВыходныхДнейОрганизаций.Начисления КАК Начисления
ГДЕ
    Начисления.Ссылка.Проведен = ИСТИНА
    И Начисления.Сторно = ЛОЖЬ
    И Начисления.ДатаВыхода МЕЖДУ &ДатаНачала И &ДатаКонца
    И НЕ Начисления.Ссылка В (ВЫБРАТЬ СсылкаДляИсключения ИЗ ВТ_ИсправленныеДокументы)

В данном случае мы выбираем все данные, но дополнительно проверяем, чтобы ссылка текущего документа не находилась в нашем «черном списке» исправленных документов.

Вариант через Левое Соединение (рекомендуемый)

Для оптимизации производительности при работе с большими объемами данных лучше использовать ЛЕВОЕ СОЕДИНЕНИЕ. Этот метод позволяет системе эффективнее планировать выполнение запроса SQL.

Рассмотрим реализацию этого подхода:


ВЫБРАТЬ
    Начисления.Сотрудник,
    Начисления.ДатаВыхода,
    Начисления.Ссылка
ИЗ
    Документ.ОплатаПраздничныхИВыходныхДнейОрганизаций.Начисления КАК Начисления
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИсправленныеДокументы КАК Исправленные
    ПО Начисления.Ссылка = Исправленные.СсылкаДляИсключения
ГДЕ
    Начисления.Ссылка.Проведен = ИСТИНА
    И Начисления.Сторно = ЛОЖЬ
    И Исправленные.СсылкаДляИсключения ЕСТЬ NULL

Поясним логику: мы присоединяем к основной таблице список «плохих» ссылок. Если ссылка из основной таблицы найдена в списке исправленных, то поле Исправленные.СсылкаДляИсключения будет заполнено. Если же документ является актуальным (его никто не исправлял), то после соединения в этом поле будет значение NULL. Условие ЕСТЬ NULL оставляет в итоговой выборке только актуальные данные.

Почему запросы к регистрам могут быть лучше?

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

Если мы будем делать запрос к виртуальной таблице регистра (например, РегистрРасчета.Начисления.ФактическийПериодДействия), система автоматически «схлопнет» исходную запись и сторнирующую запись за прошлый период. В результате в выборку попадет только итоговое, актуальное значение. Однако, если для отчета критически важны специфические реквизиты табличных частей документа (например, конкретные даты выходов, которые не всегда попадают в регистр в нужном разрезе), использование вышеописанной методики с временными таблицами является оправданным.

Важные замечания по реализации

  1. Цепочки исправлений: Если документ «А» исправлен документом «Б», а тот исправлен документом «В», вышеуказанная логика все равно сработает корректно. И «А», и «Б» попадут в таблицу исключений, так как они оба являются «перерассчитываемыми» для последующих звеньев.
  2. Отбор по сотруднику: Если вы делаете отчет по конкретному сотруднику, добавляйте этот отбор в оба запроса пакета. Это позволит уменьшить размер временной таблицы и ускорить выполнение кода.
  3. Статус документа: Всегда проверяйте свойство Проведен. Помеченные на удаление или просто записанные документы-исправления не должны влиять на актуальность исходных документов.

Таким образом, мы рассмотрели надежный способ фильтрации документов в запросе. Использование временных таблиц с индексацией и последующим левым соединением — это стандарт индустрии 1С, обеспечивающий высокую скорость работы и корректность данных в отчетах любой сложности.

← На главную