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

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

При разработке сложных отчетов или печатных форм в 1С часто возникает необходимость объединить данные из двух разных документов. Например, нам нужно взять информацию из «Группового акта» и дополнить её деталями из индивидуального «Акта расследования». Казалось бы, задача тривиальная: используем ЛЕВОЕ СОЕДИНЕНИЕ и получаем результат. Однако многие начинающие (и не только) разработчики сталкиваются с тем, что запрос возвращает пустые поля (NULL) или работает некорректно.

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

Суть проблемы: попытка соединения по Ссылке

Давайте рассмотрим типичную ситуацию. У нас есть два вида документов:

  1. Документ А (например, «АктРасследованияНС» — индивидуальный).
  2. Документ Б (например, «АктРасследованияГрупповогоНС» — общий).

Задача: выбрать данные из табличной части Документа А и присоединить к ним соответствующие строки из табличной части Документа Б. Часто интуитивное решение выглядит так:


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

Мы запускаем этот запрос и видим, что поля из ДокБ всегда пустые (NULL). Почему так происходит? Давайте разберемся в архитектуре базы данных 1С.

Почему условие «Документ1.Ссылка = Документ2.Ссылка» никогда не работает?

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

Когда мы пишем условие ПО ДокА.Ссылка = ДокБ.Ссылка, мы просим систему найти в таблице «АктРасследованияГрупповогоНС» запись, у которой ссылка в точности равна ссылке из таблицы «АктРасследованияНС». Это невозможно по двум причинам:

  1. Разные типы данных: Ссылка на документ одного вида никогда не равна ссылке на документ другого вида. Это разные объекты метаданных.
  2. Уникальность GUID: Даже если бы мы сравнивали просто уникальные идентификаторы (UUID), вероятность их совпадения у двух разных объектов стремится к нулю (и технически это разные сущности).

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

Правильный алгоритм соединения: поиск ключа связи

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

Существует два основных варианта связи:

Вариант 1. Ссылка на документ-основание

В одном из документов (обычно в подчиненном) есть реквизит, в котором хранится ссылка на родительский документ. Например, в «АктеРасследованияНС» может быть реквизит ДокументОснование, который указывает на «АктРасследованияГрупповогоНС».

В этом случае запрос должен выглядеть так:


ИЗ
    Документ.АктРасследованияНС КАК ИндивидуальныйАкт
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.АктРасследованияГрупповогоНС КАК ГрупповойАкт
        ПО ИндивидуальныйАкт.ДокументОснование = ГрупповойАкт.Ссылка

Вариант 2. Связь через строковый идентификатор (UUID)

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

Представим структуру данных:

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

Реализация запроса через идентификаторы

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

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

Алгоритм действий:

  1. Выбираем данные из первой таблицы.
  2. Присоединяем вторую таблицу.
  3. В условие ПО (ON) ставим равенство идентификаторов, а не ссылок на документы.

Пример исправленного текста запроса:


ВЫБРАТЬ
    ТЧ_Индивидуальный.Ссылка КАК Документ,
    ТЧ_Индивидуальный.НомерСтроки,
    ТЧ_Индивидуальный.ОписаниеОбстоятельств,
    ЕСТЬNULL(ТЧ_Групповой.ТребованияНТД, "") КАК ТребованияНТД
ИЗ
    Документ.АктРасследованияНС.ТабличнаяЧастьОбстоятельства КАК ТЧ_Индивидуальный
        
        // Правильное соединение:
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.АктРасследованияГрупповогоНС.ТабличнаяЧастьПричины КАК ТЧ_Групповой
        
        // Условие связи не по ссылкам документов, а по ключам строк!
        ПО ТЧ_Индивидуальный.ИдентификаторПричины = ТЧ_Групповой.ИдентификаторПричины

Обратите внимание на использование функции ЕСТЬNULL. При левом соединении, если для строки из левой таблицы не нашлось соответствия в правой (например, идентификаторы не совпали), в поле ТребованияНТД будет значение NULL. При выводе в печатную форму это может вызвать ошибку. Функция ЕСТЬNULL заменяет NULL на пустую строку или другое значение по умолчанию.

Нюанс с типами данных Идентификаторов

В платформе 1С бывает путаница с типами данных для идентификаторов. Это может быть:

Если в одной таблице поле имеет тип Строка, а в другой — УникальныйИдентификатор, прямое сравнение в запросе (Поле1 = Поле2) вызовет ошибку «Несовместимые типы выражений». В этом случае потребуется приведение типов, но язык запросов 1С ограничен в средствах кастинга. Обычно разработчики конфигураций стараются использовать один тип (чаще Строку) для таких ключей связи.

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

Как отлаживать такие запросы?

Если запрос все равно не возвращает данные, рекомендуем воспользоваться специальной консолью запросов. Действуем по шагам:

  1. Шаг 1. Сделайте выборку только из первой таблицы (Индивидуальный акт). Выведите поле, которое вы считаете ключом связи (например, ИдентификаторПричины). Скопируйте одно значение.
  2. Шаг 2. Сделайте выборку только из второй таблицы (Групповой акт). Поставьте условие ГДЕ ИдентификаторПричины = &ВашеЗначение.
  3. Результат:
    • Если второй запрос ничего не нашел — значит, ключи физически отличаются (или вы смотрите не те поля).
    • Если второй запрос нашел запись — значит, данные есть, и проблема была в синтаксисе соединения (JOIN).

Итог

Подводя итог разбора проблемы:

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

← На главную