При работе с прямыми 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 внутри таблицы самого справочника, так как записи в ней всегда принадлежат одному виду.
Первое, что необходимо сделать — убедиться, что поле, отвечающее за вид объекта (в нашем примере Док_вид), имеет одинаковый тип данных в обеих частях объединения. Посмотрим на структуру файла 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
Поскольку запрос выполняется к таблице _1SUPDTS, мы можем извлечь пользу из ее внутренней структуры. В этой таблице поле TypeID уже содержит внутренний идентификатор типа объекта метаданных. Для документов он совпадает с IDDocDef, а для справочников содержит их уникальный ID. Проанализируем ситуацию: использование U.TypeID вместо ручного указания NULL или 0 сделает запрос более универсальным и решит проблему несоответствия типов.
Важный момент при использовании 1C++: типизация вида [ИмяПоля $Тип] корректно работает в SELECT, но внутри UNION ALL она может вести себя непредсказуемо, если типы в разных частях запроса различаются (например, $Документ и $Справочник.Переоценки).
Разберем по шагам, как правильно обрабатывать типизацию в объединениях:
$Объект. Для этого идентификатор должен быть 13-символьным (4 символа ID типа + 9 символов ID объекта).SELECT.Посмотрим на структуру запроса еще раз. Часто ошибка возникает из-за банального несовпадения количества колонок. В 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 ...
При написании таких запросов рекомендуем придерживаться следующих правил:
1Cv7.DDS. Если поле в одной таблице CHAR(9), а в другой вы подставляете NULL, SQL Server может интерпретировать NULL как INT, что вызовет ошибку. Используйте CAST(NULL AS CHAR(9)) для явного указания.UNION сначала выполните части запроса по отдельности. Это поможет быстро найти, в каком блоке допущена ошибка.UNION ALL предпочтительнее простого UNION, так как оно работает быстрее, не выполняя операцию поиска и удаления дубликатов строк.Таким образом, для решения проблемы автора необходимо: во-первых, заменить NULL на 0 или U2.TypeID для совпадения типов с IDDocDef; во-вторых, выровнять количество колонок в обоих запросах; в-третьих, убрать избыточную типизацию из второй части объединения. Эти действия позволят SQL-серверу корректно обработать набор данных, а парсеру 1C++ — правильно интерпретировать результаты для передачи в среду 1С.