При работе с банковскими документами в системе 1С:Предприятие часто возникает задача сформировать выборку, которая включала бы не только уже проведенные документы (зафиксированные в учете), но и те, которые были отмечены как оплаченные, но по каким-то причинам еще не проведены. Это особенно актуально при интеграции с системами «Клиент-Банк», когда документы загружаются со статусом Оплачено, но требуют дальнейшей проверки бухгалтером перед проведением. В данной статье мы подробно разберем, как правильно составить запрос для таких целей, проанализируем различные варианты условий и рассмотрим способы оптимизации производительности.
Рассмотрим ситуацию, когда нам необходимо выбрать данные из документа ПлатежноеПоручениеИсходящее и его табличной части РасшифровкаПлатежа. Основная сложность заключается в том, чтобы корректно объединить условия по дате, пометке удаления и двум разным статусам: Проведен и Оплачено.
Первоначальный запрос обычно содержит жесткое ограничение только на проведенные документы. Разберем, как расширить это условие. Логика проста: нам нужны документы, которые либо проведены, либо (если не проведены) имеют установленный признак оплаты.
Рассмотрим пример реализации такого условия в секции ГДЕ:
ГДЕ
ПлатежноеПоручениеИсходящее.ПометкаУдаления = ЛОЖЬ
И ПлатежноеПоручениеИсходящее.ДатаОплаты >= &Дата1
И ПлатежноеПоручениеИсходящее.ДатаОплаты <= &Дата2
И (ПлатежноеПоручениеИсходящее.Проведен = ИСТИНА
ИЛИ (ПлатежноеПоручениеИсходящее.Проведен = ЛОЖЬ
И ПлатежноеПоручениеИсходящее.Оплачено = ИСТИНА))
В данном примере мы используем скобки для группировки логических операций. Это критически важный момент, так как без скобок приоритет оператора И выше, чем ИЛИ, что может привести к неверной выборке данных (например, попадут удаленные документы или документы вне указанного периода).
Проанализируем предложенное выше условие. Логически выражение (Проведен = ИСТИНА ИЛИ (Проведен = ЛОЖЬ И Оплачено = ИСТИНА)) можно упростить. Если документ проведен, он в большинстве типовых конфигураций (например, УПП или КА 1.1) априори считается оплаченным или совершившим движение денежных средств. Поэтому условие можно сократить до более изящного вида:
ГДЕ
ПлатежноеПоручениеИсходящее.ПометкаУдаления = ЛОЖЬ
И ПлатежноеПоручениеИсходящее.ДатаОплаты МЕЖДУ &Дата1 И &Дата2
И (ПлатежноеПоручениеИсходящее.Проведен ИЛИ ПлатежноеПоручениеИсходящее.Оплачено)
Здесь мы использовали оператор МЕЖДУ для более лаконичной записи периода и сократили проверку булевых полей. В языке запросов 1С проверка Поле = ИСТИНА эквивалентна простому указанию Поле.
Иногда задача усложняется: нужно выбрать документы, которые не проведены, но содержат определенный текст в комментарии (например, «Загружен из Клиент-Банка»). Это часто требуется для отслеживания импортированных, но необработанных платежей.
Рассмотрим пример запроса для документа ПлатежныйОрдерСписаниеДенежныхСредств:
ВЫБРАТЬ
ПлатежныйОрдер.Ссылка КАК Ссылка,
ПлатежныйОрдер.Номер КАК Номер,
ПлатежныйОрдер.Дата КАК Дата,
ПлатежныйОрдер.СуммаДокумента КАК Сумма
ИЗ
Документ.ПлатежныйОрдерСписаниеДенежныхСредств КАК ПлатежныйОрдер
ГДЕ
ПлатежныйОрдер.ПометкаУдаления = ЛОЖЬ
И ПлатежныйОрдер.Дата МЕЖДУ &Дата1 И &Дата2
И (ПлатежныйОрдер.Проведен = ИСТИНА
ИЛИ (ПлатежныйОрдер.Проведен = ЛОЖЬ
И ПлатежныйОрдер.Комментарий ПОДОБНО "%Загружен из Клиент-Банка%"))
Выясним причину, почему использование оператора ПОДОБНО с процентом в начале строки является «тяжелой» операцией. При таком условии СУБД не может использовать индексы для поиска и вынуждена выполнять полное сканирование таблицы (Full Scan), что на больших объемах данных приведет к значительным задержкам. Если такая выборка выполняется часто, рекомендуется добавить в документ дополнительный реквизит (флаг или перечисление) ИсточникПоступления, который будет заполняться при загрузке.
Рассмотрим продвинутый метод оптимизации. Когда в секции ГДЕ используется ИЛИ, планировщик запросов СУБД часто выбирает не самый оптимальный план. Чтобы гарантировать использование индексов по полям Дата и Проведен, эффективнее разделить запрос на две части и объединить их.
Разберем этот подход на примере:
ВЫБРАТЬ
Т.Ссылка, Т.СуммаДокумента
ИЗ
Документ.ПлатежноеПоручениеИсходящее КАК Т
ГДЕ
Т.ДатаОплаты МЕЖДУ &Дата1 И &Дата2
И Т.Проведен = ИСТИНА
И Т.ПометкаУдаления = ЛОЖЬ
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т.Ссылка, Т.СуммаДокумента
ИЗ
Документ.ПлатежноеПоручениеИсходящее КАК Т
ГДЕ
Т.ДатаОплаты МЕЖДУ &Дата1 И &Дата2
И Т.Проведен = ЛОЖЬ
И Т.Оплачено = ИСТИНА
И Т.ПометкаУдаления = ЛОЖЬ
Такой подход позволяет системе отдельно и быстро найти все проведенные документы за период, а затем отдельно найти непроведенные, но оплаченные. UNION ALL работает быстрее, чем обычный UNION, так как не выполняет проверку на дубликаты строк, что в данном случае и не требуется (один и тот же документ не может быть одновременно проведен и не проведен).
В исходных примерах часто встречается ПОЛНОЕ СОЕДИНЕНИЕ между документом и его табличной частью. Проанализируем ситуацию: полное соединение в данном контексте обычно избыточно. Если нам нужны данные из расшифровки платежа (например, статья ДДС), лучше использовать ЛЕВОЕ СОЕДИНЕНИЕ или вообще строить запрос от таблицы РасшифровкаПлатежа.
При использовании соединений важно помнить про значение NULL. Если в документе не заполнена табличная часть, поля этой части в результате запроса будут содержать NULL. Чтобы избежать ошибок при расчетах, используйте функцию ЕСТЬNULL:
ВЫБРАТЬ
ПлатежноеПоручение.Ссылка КАК Ссылка,
ЕСТЬNULL(ПлатежноеПоручениеРасшифровка.СуммаПлатежа, 0) КАК СуммаРасшифровки
ИЗ
Документ.ПлатежноеПоручениеИсходящее КАК ПлатежноеПоручение
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПлатежноеПоручениеИсходящее.РасшифровкаПлатежа КАК ПлатежноеПоручениеРасшифровка
ПО (ПлатежноеПоручениеРасшифровка.Ссылка = ПлатежноеПоручение.Ссылка)
Напоследок разберем самый архитектурно правильный метод. Если ваша конфигурация использует регистры накопления для учета денежных средств (как в УПП, Комплексной автоматизации или ERP), то для получения информации о «прошедших» платежах правильнее обращаться к виртуальным таблицам оборотов регистров, например, ДенежныеСредства или ДенежныеСредстваКПриходу.
Преимущества работы с регистрами:
Однако, если стоит специфическая задача найти именно непроведенные документы с пометкой оплаты (которые еще не попали в регистры), то использование запроса к таблицам документов, как мы разобрали выше, остается единственным верным решением.