Почему в запросе 1С 7.7 не выводится дата документа из реквизита неопределенного типа?

Программист 1С v7.7 Управленческий учет
← На главную

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

Причина проблемы: Особенности типизации в 1С 7.7

Разберем внутреннюю механику платформы. В 1С 7.7 реквизит типа Документ без указания конкретного вида называется реквизитом неопределенного типа. В базе данных такие значения хранятся в виде составного идентификатора: первые символы определяют вид документа, остальные — его уникальный номер (ID) в системе. Стандартный движок запросов 1С 7.7 не обладает механизмом автоматического разыменования (автоматического соединения таблиц) для таких полей. Когда мы пишем в запросе ДатаДок = Справочник.Партии.ПриходныйДокумент.ДатаДок, система не знает, к таблице какого именно документа (например, ПоступлениеТМЦ или ОприходованиеТМЦ) ей нужно обратиться, чтобы считать поле даты.

Решение 1: Явное перечисление видов документов

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


ТекстЗапроса = "
|Номенклатура = Справочник.Партии.Владелец;
|ПриходныйДокумент = Справочник.Партии.ПриходныйДокумент;
|ДатаДок = Справочник.Партии.ПриходныйДокумент.ПоступлениеТМЦ.ДатаДок,
|          Справочник.Партии.ПриходныйДокумент.ОприходованиеТМЦ.ДатаДок,
|          Справочник.Партии.ПриходныйДокумент.ВозвратОтПокупателя.ДатаДок;
|Группировка Номенклатура;
|Группировка ПриходныйДокумент;
|";

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

Решение 2: Обращение к атрибуту объекта в цикле обхода

Если нам не нужно сортировать результаты запроса по дате или накладывать условия на дату непосредственно в тексте запроса, мы можем получить её гораздо проще. Выясним, как это сделать: достаточно просто выбрать сам документ в запросе, а дату получить при обработке результата.


Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        Пока Запрос.Группировка(2) = 1 Цикл
            // В переменной Док находится ссылка на документ
            Док = Запрос.ПриходныйДокумент;
            // Обращаемся к атрибуту объекта напрямую
            ДатаДокумента = Док.ДатаДок; 
            Сообщить("Документ: " + Док + " от " + ДатаДокумента);
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

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

Решение 3: Динамическая сборка текста запроса через метаданные

Чтобы не перечислять десятки видов документов вручную, мы можем автоматизировать процесс, используя объект Метаданные. Посмотрим на пример функции, которая сформирует нужную строку для запроса:


Функция СформироватьПутиКДате(ИмяСправочника, ИмяРеквизита)
    Результат = "";
    Для ии = 1 По Метаданные.Документ() Цикл
        ИмяДока = Метаданные.Документ(ии).Идентификатор;
        Результат = Результат + "Справочник." + ИмяСправочника + "." + ИмяРеквизита + "." + ИмяДока + ".ДатаДок,";
    КонецЦикла;
    // Удаляем последнюю запятую
    Возврат Лев(Результат, СтрДлина(Результат)-1);
КонецФункции

Использование такой функции позволит динамически подставить в текст запроса все существующие в конфигурации типы документов, что полностью решает проблему "пустых дат" без ручного кодинга.

Решение 4: Использование регистров вместо справочников

Проанализируем ситуацию с точки зрения архитектуры 1С. Если задача стоит в получении первых дат партий (как в примере автора темы), то обращение к справочнику Партии — не самый оптимальный путь. В типовых конфигурациях (например, "Торговля и Склад") информация о движениях партий хранится в регистрах (например, ПартииНаличие).

В запросах к регистрам существует служебное поле ТекущийДокумент. Оно всегда типизировано и позволяет получить дату без лишних ухищрений. Посмотрим на пример логики:

  1. Делаем запрос к движениям регистра ПартииНаличие.
  2. Используем ТекущийДокумент.ДатаДок.
  3. Устанавливаем фильтр по нужной номенклатуре.

Это решение будет работать значительно быстрее, так как оно опирается на индексы таблиц движений, а не на полный перебор справочника.

Решение 5: Прямые SQL-запросы (для продвинутых пользователей)

Если ваша база работает на MS SQL Server и вы используете внешние компоненты, такие как 1С++, проблему можно решить одним эффективным запросом. В таблицах SQL данные о датах всех документов хранятся в одной общей таблице _1SJOURN. Нам достаточно соединить (JOIN) таблицу справочника партий с таблицей журнала документов по полю IDDoc. Это позволит мгновенно получить даты для любого количества записей, игнорируя любые ограничения встроенного языка запросов 1С.

Важно помнить: При работе со справочником "Партии" всегда проверяйте, что документ в реквизите ПриходныйДокумент действительно существует (не был удален или помечен на удаление), так как в 1С 7.7 возможны "битые" ссылки, которые также приведут к пустой дате при любых способах обращения.

← На главную