При разработке сложных отчетов или печатных форм в 1С часто возникает необходимость объединить данные из двух разных документов. Например, нам нужно взять информацию из «Группового акта» и дополнить её деталями из индивидуального «Акта расследования». Казалось бы, задача тривиальная: используем ЛЕВОЕ СОЕДИНЕНИЕ и получаем результат. Однако многие начинающие (и не только) разработчики сталкиваются с тем, что запрос возвращает пустые поля (NULL) или работает некорректно.
В этой статье мы проведем анализ конфигурации на наличие ошибок и подробно разберем, почему стандартный подход к соединению документов может не сработать, проанализируем ошибку соединения по полю Ссылка и рассмотрим правильный алгоритм построения запроса на примере задачи из реальной практики.
Давайте рассмотрим типичную ситуацию. У нас есть два вида документов:
Задача: выбрать данные из табличной части Документа А и присоединить к ним соответствующие строки из табличной части Документа Б. Часто интуитивное решение выглядит так:
ВЫБРАТЬ
ДокА.Ссылка,
ДокБ.КакоеТоПоле
ИЗ
Документ.АктРасследованияНС КАК ДокА
ЛЕВОЕ СОЕДИНЕНИЕ Документ.АктРасследованияГрупповогоНС КАК ДокБ
ПО ДокА.Ссылка = ДокБ.Ссылка
Мы запускаем этот запрос и видим, что поля из ДокБ всегда пустые (NULL). Почему так происходит? Давайте разберемся в архитектуре базы данных 1С.
В платформе 1С:Предприятие каждый вид документа хранится в своей собственной таблице базы данных (если говорить упрощенно). Поле Ссылка (Ref) является уникальным идентификатором записи именно внутри этой таблицы (или в рамках таблицы ссылочных типов, но суть остается прежней — это указатель на конкретный объект конкретного типа).
Когда мы пишем условие ПО ДокА.Ссылка = ДокБ.Ссылка, мы просим систему найти в таблице «АктРасследованияГрупповогоНС» запись, у которой ссылка в точности равна ссылке из таблицы «АктРасследованияНС». Это невозможно по двум причинам:
Важное правило: Никогда не соединяйте разные виды документов напрямую через равенство их ссылок. Это условие всегда будет ложным.
Чтобы выполнить быстрый анализ данных и корректно соединить данные двух разных документов, нам необходимо найти общий критерий или ключ связи. Давайте проанализируем, как документы могут быть связаны логически.
Существует два основных варианта связи:
В одном из документов (обычно в подчиненном) есть реквизит, в котором хранится ссылка на родительский документ. Например, в «АктеРасследованияНС» может быть реквизит ДокументОснование, который указывает на «АктРасследованияГрупповогоНС».
В этом случае запрос должен выглядеть так:
ИЗ
Документ.АктРасследованияНС КАК ИндивидуальныйАкт
ЛЕВОЕ СОЕДИНЕНИЕ Документ.АктРасследованияГрупповогоНС КАК ГрупповойАкт
ПО ИндивидуальныйАкт.ДокументОснование = ГрупповойАкт.Ссылка
В более сложных сценариях, особенно когда речь идет о синхронизации табличных частей (как в рассматриваемой нами задаче), связь может быть реализована не через объектную ссылку, а через специальный идентификатор строки.
Представим структуру данных:
ИдентификаторСтроки типа Строка или УникальныйИдентификатор).Именно этот случай обсуждался в исходной теме. Автор упоминал поле ИдентификаторПричины, которое, судя по всему, является ключом синхронизации.
Давайте построим правильный запрос, исправляя ошибку автора. Нам нужно соединить не шапки документов по ссылке, а табличные части по их смысловому ключу.
Предположим, структура данных такова:
ИдентификаторСвязи.ИдентификаторСвязи и нужные нам данные (например, ТребованияНТД).Алгоритм действий:
ПО (ON) ставим равенство идентификаторов, а не ссылок на документы.Пример исправленного текста запроса:
ВЫБРАТЬ
ТЧ_Индивидуальный.Ссылка КАК Документ,
ТЧ_Индивидуальный.НомерСтроки,
ТЧ_Индивидуальный.ОписаниеОбстоятельств,
ЕСТЬNULL(ТЧ_Групповой.ТребованияНТД, "") КАК ТребованияНТД
ИЗ
Документ.АктРасследованияНС.ТабличнаяЧастьОбстоятельства КАК ТЧ_Индивидуальный
// Правильное соединение:
ЛЕВОЕ СОЕДИНЕНИЕ Документ.АктРасследованияГрупповогоНС.ТабличнаяЧастьПричины КАК ТЧ_Групповой
// Условие связи не по ссылкам документов, а по ключам строк!
ПО ТЧ_Индивидуальный.ИдентификаторПричины = ТЧ_Групповой.ИдентификаторПричины
Обратите внимание на использование функции ЕСТЬNULL. При левом соединении, если для строки из левой таблицы не нашлось соответствия в правой (например, идентификаторы не совпали), в поле ТребованияНТД будет значение NULL. При выводе в печатную форму это может вызвать ошибку. Функция ЕСТЬNULL заменяет NULL на пустую строку или другое значение по умолчанию.
В платформе 1С бывает путаница с типами данных для идентификаторов. Это может быть:
УникальныйИдентификатор (стандартный системный тип).Строка (длиной 36 символов).Если в одной таблице поле имеет тип Строка, а в другой — УникальныйИдентификатор, прямое сравнение в запросе (Поле1 = Поле2) вызовет ошибку «Несовместимые типы выражений». В этом случае потребуется приведение типов, но язык запросов 1С ограничен в средствах кастинга. Обычно разработчики конфигураций стараются использовать один тип (чаще Строку) для таких ключей связи.
Если вы столкнулись с такой проблемой, проверьте типы полей в дереве метаданных конфигуратора. Если типы разные, возможно, придется использовать временные таблицы и в одной из них привести идентификатор к нужному типу перед соединением.
Если запрос все равно не возвращает данные, рекомендуем воспользоваться специальной консолью запросов. Действуем по шагам:
ИдентификаторПричины). Скопируйте одно значение.ГДЕ ИдентификаторПричины = &ВашеЗначение.Подводя итог разбора проблемы:
Ссылка — грубая логическая ошибка. Ссылки разных таблиц никогда не равны.ЛЕВОЕ СОЕДИНЕНИЕ аккуратно, обрабатывая возможные NULL значения.Применяя этот подход, вы сможете корректно формировать данные для печатных форм, объединяя информацию из цепочек связанных документов любой сложности.