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

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

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

Постановка задачи и базовое решение

Начнем с простейшего сценария. Нам необходимо узнать общее количество проведенных и непроведенных документов конкретного вида (например, ЗаказПокупателя). На первый взгляд, задача решается элементарным запросом с группировкой по стандартному реквизиту Проведен.

Давайте проанализируем базовый вариант запроса:


ВЫБРАТЬ
    КОЛИЧЕСТВО(ЗаказПокупателя.Ссылка) КАК Количество,
    ЗаказПокупателя.Проведен КАК СтатусПроведения
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя

СГРУППИРОВАТЬ ПО
    ЗаказПокупателя.Проведен

Такой запрос вернет нам две строки. В одной строке будут сгруппированы проведенные документы (где значение реквизита Проведен равно Истина), во второй — все остальные (где значение равно Ложь). Однако этот простой подход таит в себе важную методологическую ошибку, которую мы разберем далее.

Проблема трех статусов: проведенные, непроведенные и помеченные на удаление

Дело в том, что в реальной базе данных документы, у которых реквизит Проведен имеет значение Ложь, делятся на две абсолютно разные по смыслу категории:

  1. Просто непроведенные документы. Это черновики, новые документы или документы, проведение которых было отменено пользователем. Они актуальны и могут быть проведены в будущем.
  2. Помеченные на удаление документы. Это объекты, которые пользователи подготовили к удалению из системы. Они также технически не проведены, но их жизненный цикл в системе практически завершен.

Если мы используем базовый запрос, то помеченные на удаление документы «смешаются» в одной куче с обычными непроведенными черновиками. Это исказит реальную картину статистики.

Чтобы получить детальную информацию сразу по трем статусам (Проведен, Не проведен, Помечен на удаление), нам необходимо задействовать логическую конструкцию ВЫБОР КОГДА как в поле выборки, так и в секции группировки запроса.

Рассмотрим оптимальный и правильный вариант запроса:


ВЫБРАТЬ
    ВЫБОР
        КОГДА ЗаказПокупателя.ПометкаУдаления ТОГДА "Помечен на удаление"
        КОГДА ЗаказПокупателя.Проведен ТОГДА "Проведен"
        ИНАЧЕ "Не проведен"
    КОНЕЦ КАК СтатусДокумента,
    КОЛИЧЕСТВО(ЗаказПокупателя.Ссылка) КАК Количество
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя

СГРУППИРОВАТЬ ПО
    ВЫБОР
        КОГДА ЗаказПокупателя.ПометкаУдаления ТОГДА "Помечен на удаление"
        КОГДА ЗаказПокупателя.Проведен ТОГДА "Проведен"
        ИНАЧЕ "Не проведен"
    КОНЕЦ

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

Технические нюансы платформы: возможен ли статус «Проведен и Удален»?

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

При штатной работе пользователя в интерфейсе или при вызове стандартных методов программного кода такое состояние невозможно:

Тем не менее, на практике программисты иногда сталкиваются с такими «документами-кентаврами». Как такое происходит?

  1. Ошибки обмена данными (РИБ или внешняя синхронизация). Если в базу загружаются данные в режиме ОбменДанными.Загрузка = Истина, платформа отключает большинство стандартных бизнес-процедур и проверок, записывая данные напрямую «как есть». Если в файле обмена из-за программного сбоя присутствовали некорректные статусы, они физически запишутся в СУБД.
  2. Прямая модификация СУБД. В клиент-серверных базах данных администратор или злоумышленник может выполнить прямой SQL-запрос к таблицам базы данных (например, к полям _Posted и _Marked), минуя сервер приложений 1С.

Наличие таких документов в базе крайне опасно: они могут содержать активные движения по регистрам (и влиять на баланс, отчетность, остатки), но визуально отображаться как помеченные на удаление. Для выявления и устранения таких проблем рекомендуется регулярно проводить процедуру «Тестирование и исправление» информационной базы в конфигураторе (с включенной проверкой логической целостности объектов).

Как получить статистику по всем видам документов в базе данных?

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

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

Давайте разберем по шагам готовый рабочий алгоритм:


ТекстЗапроса = "";
ПервыйДокумент = Истина;

Для Каждого МетаДокумент Из Метаданные.Документы Цикл
    
    // Проверяем, разрешено ли для данного документа проведение в принципе
    Если МетаДокумент.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
        
        ИмяДокумента = МетаДокумент.Имя;
        СинонимДокумента = МетаДокумент.Синоним;
        Если Не ЗначениеЗаполнено(СинонимДокумента) Тогда
            СинонимДокумента = ИмяДокумента;
        КонецЕсли;
        
        Если Не ПервыйДокумент Тогда
            ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
        КонецЕсли;
        
        ТекстЗапроса = ТекстЗапроса + 
        "ВЫБРАТЬ
        |   """ + СинонимДокумента + """ КАК ВидДокумента,
        |   ВЫБОР
        |       КОГДА Док.ПометкаУдаления ТОГДА ""Помечен на удаление""
        |       КОГДА Док.Проведен ТОГДА ""Проведен""
        |       ИНАЧЕ ""Не проведен""
        |   КОНЕЦ КАК Статус,
        |   КОЛИЧЕСТВО(Док.Ссылка) КАК Количество
        |ИЗ
        |   Документ." + ИмяДокумента + " КАК Док
        |
        |СГРУППИРОВАТЬ ПО
        |   ВЫБОР
        |       КОГДА Док.ПометкаУдаления ТОГДА ""Помечен на удаление""
        |       КОГДА Док.Проведен ТОГДА ""Проведен""
        |       ИНАЧЕ ""Не проведен""
        |   КОНЕЦ";
        
        ПервыйДокумент = Ложь;
        
    КонецЕсли;
    
КонецЦикла;

Если ЗначениеЗаполнено(ТекстЗапроса) Тогда
    Запрос = Новый Запрос(ТекстЗапроса);
    РезультатЗапроса = Запрос.Выполнить();
    ТаблицаСтатистики = РезультатЗапроса.Выгрузить();
    // Полученную таблицу значений теперь можно вывести в отчет или форму
КонецЕсли;

Этот программный код автоматически сформирует единый тяжелый запрос ко всем таблицам документов, выполнит его на стороне СУБД и вернет удобную плоскую таблицу с колонками ВидДокумента, Статус и Количество.

Влияние на производительность системы и блокировки

Выполняя подобные аналитические запросы, особенно по всей базе данных, необходимо помнить о производительности и стабильности работы пользователей в системе.

Подсчет общего количества записей в таблицах СУБД с группировкой по неиндексированным или слабоиндексированным полям (какими часто являются Проведен и ПометкаУдаления) заставляет СУБД выполнять операцию полного сканирования таблиц (Table Scan или Index Scan).

Если база данных имеет внушительный объем (сотни гигабайт или терабайты данных, миллионы документов), запуск подобного запроса «в лоб» в разгар рабочего дня может привести к следующим неприятным последствиям:

Рекомендации по безопасной работе: Чтобы избежать негативного влияния на производительность, старайтесь выполнять подобные глобальные аналитические срезы в периоды минимальной активности пользователей (в технологическое окно ночью) либо на тестовой копии информационной базы. Если статистику необходимо собрать в рабочей базе прямо сейчас, обязательно ограничивайте выборку разумным периодом дат с помощью конструкции ГДЕ Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода, поскольку по полю Дата в таблицах документов 1С практически всегда присутствует эффективный индекс СУБД.

← На главную