Как выбрать все документы конфигурации в 1С и поместить их во временную таблицу?

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

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

Разберем основные подходы к решению этой задачи: от динамического построения пакетных запросов до перебора через менеджеры объектов, а также рассмотрим важные технические нюансы оптимизации производительности.

Способ 1. Программная генерация текста запроса через коллекцию метаданных

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

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

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


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

Для Каждого МДДокумент Из Метаданные.Документы Цикл
    
    // Пропускаем документы, не сохраняемые в базе данных
    Если НЕ МДДокумент.Таблица Тогда
        Продолжить;
    КонецЕсли;

    Если Не Первый Тогда
        ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС;
    КонецЕсли;

    ТекстЗапроса = ТекстЗапроса + 
        "ВЫБРАТЬ
        |    Док.Ссылка КАК Ссылка,
        |    Док.Дата КАК Дата,
        |    Док.ПометкаУдаления КАК ПометкаУдаления
        |ИЗ
        |    Документ." + МДДокумент.Имя + " КАК Док
        |ГДЕ
        |    Док.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
        |    И Док.ПометкаУдаления = &ПометкаУдаления";

    // Проверяем возможность проведения документа
    Если МДДокумент.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
        ТекстЗапроса = ТекстЗапроса + "
        |    И Док.Проведен = &Проведен";
    КонецЕсли;

    Первый = Ложь;

КонецЦикла;

// Оборачиваем во временную таблицу
ТекстЗапроса = "ВЫБРАТЬ
               |    ВТ.Ссылка КАК Ссылка,
               |    ВТ.Дата КАК Дата,
               |    ВТ.ПометкаУдаления КАК ПометкаУдаления
               |ПОМЕСТИТЬ ВТ_ВсеДокументы
               |ИЗ
               |    (" + ТекстЗапроса + ") КАК ВТ
               |;
               |ВЫБРАТЬ * ИЗ ВТ_ВсеДокументы КАК ВТ_ВсеДокументы";

Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ПометкаУдаления", Ложь);
Запрос.УстановитьПараметр("Проведен", Истина);

РезультатЗапроса = Запрос.Выполнить();

Способ 2. Выборка через менеджеры документов и передача таблицы значений в запрос

Если требуется обработать документы без динамической склейки сложного SQL-запроса, можно последовательно перебрать документы через объектную модель, выгрузить ссылки в ТаблицаЗначений и передать ее параметром во временную таблицу запроса.

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


ТЗДокументов = Новый ТаблицаЗначений;
ТЗДокументов.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("ДокументСсылка"));
ТЗДокументов.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));

Для Каждого ДокМенеджер Из Документы Цикл
    Выборка = ДокМенеджер.Выбрать(НачалоДня(ТекущаяДата()), КонецДня(ТекущаяДата()));
    Пока Выборка.Следующий() Цикл
        // Проверяем нужные условия
        Если Выборка.ПометкаУдаления = Ложь И Выборка.Проведен = Истина Тогда
            НоваяСтрока = ТЗДокументов.Добавить();
            НоваяСтрока.Ссылка = Выборка.Ссылка;
            НоваяСтрока.Дата = Выборка.Дата;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

// Помещаем полученную таблицу в запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТЗ.Ссылка КАК Ссылка,
    |    ТЗ.Дата КАК Дата
    |ПОМЕСТИТЬ ВТ_Документы
    |ИЗ
    |    &ТЗДокументов КАК ТЗ";

Запрос.УстановитьПараметр("ТЗДокументов", ТЗДокументов);
Результат = Запрос.Выполнить();

Важно: этот способ значительно медленнее запросов к СУБД на больших объемах данных, так как считывает объекты в оперативную память сервера приложений построчно, однако он прост в отладке и не зависит от ограничений СУБД на количество объединений в одном запросе.

Ограничения и рекомендации по оптимизации

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

  1. Ограничения СУБД на объем запроса: Если в конфигурации сотни видов документов, единый запрос с сотнями секций ОБЪЕДИНИТЬ ВСЕ вызовет долгую компиляцию плана запроса СУБД или ошибку переполнения стека. Рекомендуется разбивать обход метаданных на пакеты по 20–30 документов и последовательно наполнять временную таблицу через ПОМЕСТИТЬ.
  2. Индексация и фильтрация по периоду: Стандартный реквизит Дата всегда проиндексирован. Указание границ периода в секции ГДЕ обязательно, иначе СУБД выполнит полное сканирование (Table Scan) всех таблиц за всю историю базы.
  3. Влияние RLS: При включенном ограничении прав на уровне записей к каждому объединенному блоку добавляются скрытые подзапросы проверки прав, что многократно увеличивает нагрузку на сервер. По возможности такие выборки выполняются в привилегированном режиме.
← На главную