Как объединить данные документов и справочников в одном SQL-запросе в 1С 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе с прямыми SQL-запросами в среде 1С:Предприятие 7.7 (особенно при использовании внешней компоненты 1C++) разработчики часто сталкиваются с необходимостью объединить данные из разных физических таблиц — например, из журнала документов и таблицы конкретного справочника. Основная сложность здесь заключается в использовании оператора UNION ALL, который предъявляет строгие требования к количеству колонок и их типам данных. Рассмотрим подробнее, как решить проблему типизации и корректно составить такой запрос.

Разбор проблемы: почему возникает ошибка в поле вида объекта

Проанализируем ситуацию: автор пытается объединить данные из таблицы регистрации изменений УРБД (_1SUPDTS) для документов и справочников. В первой части запроса (для документов) используется поле J.IDDocDef, которое в SQL-базе 1С 7.7 имеет числовой тип (Integer). Во второй части (для справочников) на этом же месте стоит NULL.

Система SQL Server при выполнении UNION ALL определяет тип колонки по первой части запроса. Если в первом блоке это целое число, а во втором — NULL без явного указания типа, это может привести к конфликту типов при попытке парсера 1C++ наложить типизацию метаданных (например, $Документ). Выясним причину ошибки: для справочников в 1С 7.7 нет прямого аналога поля IDDocDef внутри таблицы самого справочника, так как записи в ней всегда принадлежат одному виду.

Решение 1: Выравнивание типов данных в колонках

Первое, что необходимо сделать — убедиться, что поле, отвечающее за вид объекта (в нашем примере Док_вид), имеет одинаковый тип данных в обеих частях объединения. Посмотрим на структуру файла 1Cv7.DDS: поле IDDOCDEF определено как I (Integer). Следовательно, вместо NULL во второй части запроса следует использовать 0 или идентификатор метаданных этого справочника.

Рассмотрим пример исправленного кода, где мы явно указываем числовое значение:


|SELECT
|    U.OBJID as [Док $Документ],
|    J.IDDocDef as Док_вид,
|    U.DBSIGN,
|    U.OBJID
|FROM
|    _1SUPDTS as U
|INNER JOIN
|    _1Sjourn as J ON U.TypeID=J.IDDocDef And U.OBJID=J.IDDoc
|
|UNION ALL
|
|SELECT
|    U2.OBJID, -- Убираем типизацию здесь, она берется из первой части
|    0,        -- Вместо NULL ставим 0, чтобы тип соответствовал IDDocDef
|    U2.DBSIGN,
|    U2.OBJID
|FROM
|    _1SUPDTS as U2
|INNER JOIN
|    $Справочник.Переоценки as Переоценки ON U2.OBJID=Переоценки.ID

Решение 2: Использование системного поля TypeID

Поскольку запрос выполняется к таблице _1SUPDTS, мы можем извлечь пользу из ее внутренней структуры. В этой таблице поле TypeID уже содержит внутренний идентификатор типа объекта метаданных. Для документов он совпадает с IDDocDef, а для справочников содержит их уникальный ID. Проанализируем ситуацию: использование U.TypeID вместо ручного указания NULL или 0 сделает запрос более универсальным и решит проблему несоответствия типов.

Решение 3: Проблема типизации 1C++ в UNION

Важный момент при использовании 1C++: типизация вида [ИмяПоля $Тип] корректно работает в SELECT, но внутри UNION ALL она может вести себя непредсказуемо, если типы в разных частях запроса различаются (например, $Документ и $Справочник.Переоценки).

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

  1. Откажитесь от специфической типизации в подзапросах объединения. Типизацию метаданных лучше накладывать на финальный результат или использовать универсальный тип.
  2. Если нужно объединить разные справочники и документы в одной колонке, используйте типизацию $Объект. Для этого идентификатор должен быть 13-символьным (4 символа ID типа + 9 символов ID объекта).
  3. Если вы точно знаете, что в колонке будут либо только документы, либо только справочники одного вида, оставьте типизацию только в первом SELECT.

Решение 4: Выравнивание количества полей

Посмотрим на структуру запроса еще раз. Часто ошибка возникает из-за банального несовпадения количества колонок. В UNION ALL каждый SELECT должен возвращать строго одинаковое число столбцов. Если во второй части запроса вам нужны данные из дополнительных таблиц (например, $Справочник.МестаХранения), которых нет в первой части, необходимо добавить "пустые" колонки-заглушки в первый SELECT.

Рассмотрим пример с выравниванием колонок:


|SELECT
|    U.OBJID as [Объект $Объект],
|    J.IDDocDef as ВидОбъекта,
|    NULL as [Склад $Справочник.МестаХранения] -- Заглушка для первой части
|FROM
|    _1SUPDTS as U
|INNER JOIN
|    _1Sjourn as J ON U.OBJID=J.IDDoc
|
|UNION ALL
|
|SELECT
|    U2.OBJID, 
|    U2.TypeID,
|    Склады.ID
|FROM
|    _1SUPDTS as U2
|INNER JOIN
|    $Справочник.Переоценки as Переоценки ON U2.OBJID=Переоценки.ID
|LEFT JOIN
|    $Справочник.МестаХранения as Склады ON ... 

Полезные советы по работе с SQL в 1С 7.7

При написании таких запросов рекомендуем придерживаться следующих правил:

Таким образом, для решения проблемы автора необходимо: во-первых, заменить NULL на 0 или U2.TypeID для совпадения типов с IDDocDef; во-вторых, выровнять количество колонок в обоих запросах; в-третьих, убрать избыточную типизацию из второй части объединения. Эти действия позволят SQL-серверу корректно обработать набор данных, а парсеру 1C++ — правильно интерпретировать результаты для передачи в среду 1С.

← На главную