Как выбрать последний проведённый документ каждого вида в 1С?

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

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

Способ 1. Динамическое формирование запроса через метаданные

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

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

Разберем пример кода, который формирует текст запроса:


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

Для Каждого МетаДокумент Из Метаданные.Документы Цикл
    // Проверяем, разрешено ли проведение для данного вида документа
    Если МетаДокумент.Проведение <> Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
        Продолжить;
    КонецЕсли;

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

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

    ПервыйДокумент = Ложь;
КонецЦикла;

Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить().Выгрузить();

В данном примере мы используем конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 для каждой таблицы. Это позволяет СУБД максимально быстро найти нужную запись, используя индекс по дате.

Синтаксические нюансы при использовании ОБЪЕДИНИТЬ ВСЕ

При использовании оператора ОБЪЕДИНИТЬ ВСЕ часто возникают ошибки, связанные с сортировкой. Важно помнить правило: если вы используете УПОРЯДОЧИТЬ ПО внутри объединяемых частей запроса, вы обязаны использовать ВЫБРАТЬ ПЕРВЫЕ. Кроме того, как было отмечено в ходе обсуждения, СУБД требует, чтобы поля, по которым идет сортировка, присутствовали в списке выбора каждой части объединения.

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

Способ 2. Использование подзапросов для чистоты результата

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

Рассмотрим пример структуры такого подзапроса:


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

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ПОДЗАПРОС.Ссылка
ИЗ (
    ВЫБРАТЬ ПЕРВЫЕ 1
        Т.Ссылка КАК Ссылка,
        Т.Дата КАК Дата
    ИЗ
        Документ.ПоступлениеТоваровУслуг КАК Т
    ГДЕ
        Т.Проведен = ИСТИНА
    УПОРЯДОЧИТЬ ПО
        Дата УБЫВ
) КАК ПОДЗАПРОС

Способ 3. Оптимизация через Журналы документов

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

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

  1. Определяем список типов документов, которые нас интересуют.
  2. Выполняем запрос к журналу с группировкой или использованием МАКСИМУМ(МоментВремени).

Однако стоит учитывать, что в журнале нет прямого способа выбрать "по одному первому" для каждого типа простым GROUP BY, если нам нужна именно Ссылка. В таком случае всё равно придется использовать соединение или временные таблицы, но скорость работы с одной таблицей журнала будет выше, чем с сотней разрозненных таблиц документов.

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

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

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

← На главную