Как типизировать данные из разных справочников в одном поле прямого запроса 1С 7.7

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

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

В этой статье мы подробно разберем, как заставить 1С воспринимать строковые идентификаторы SQL как полноценные объекты (справочники), и как правильно формировать составные поля для корректной типизации.

Суть проблемы: почему 1С не «видит» объект

Рассмотрим стандартную ситуацию: мы пишем прямой запрос к таблице журнала документов _1SJourn и присоединяем таблицы конкретных документов. Допустим, у нас есть «Приходный Ордер», где поле «Отправитель» — это справочник «Контрагенты», и «Отгрузка», где «Отправитель» — это справочник «Склады».

Если мы просто выберем идентификаторы этих объектов через CASE, SQL вернет нам девятисимвольные строки (ID). Для SQL-сервера это просто набор символов. Компонента 1C++ при попытке типизировать такое поле как $Справочник.Контрагенты проигнорирует значения, которые не относятся к этому справочнику. А если указать общий тип $Справочник, система не поймет, из какой именно таблицы брать объект, так как ей не хватает информации о виде справочника.

Разбор структуры идентификатора 1С 7.7

Для того чтобы решить задачу, нам нужно понять, как 1С хранит ссылки на объекты «неопределенного» типа. В системе 7.7 для этого используется строка длиной 13 символов. Она формируется по следующим правилам:

  1. Первые 4 символа: Это базовый 36-ричный идентификатор типа метаданных (ID вида объекта). Именно он говорит системе: «это справочник Контрагенты» или «это справочник Склады».
  2. Следующие 9 символов: Это уникальный идентификатор (ID) самого элемента внутри его таблицы.

Следовательно, наша задача в SQL-запросе — не просто выбрать ID, а «склеить» префикс вида объекта с его идентификатором.

Решение через макроподстановку $ВидСправочника36

Проанализируем правильный подход к написанию запроса. Для получения четырехсимвольного префикса вида справочника в 1C++ используется специальная макроподстановка $ВидСправочника36.ИмяСправочника. Рассмотрим, как это выглядит в коде запроса.


ТекстЗапроса = "
|SELECT
|    Жур.IDDoc as [Док $Документ],
|    Жур.IDDocDef Док_вид,
|
|CASE Жур.IDDocDef
|    WHEN $ВидДокумента.ПриходныйОрдер THEN $ВидСправочника36.Контрагенты + $ДокПО.Контрагент 
|    WHEN $ВидДокумента.Отгрузка THEN $ВидСправочника36.Склады + $ДокОтгр.Склад
|    ELSE $ПустойИД13
|END AS [Отправитель $Справочник]
|
|FROM
|    _1SJourn as Жур (nolock) 
|LEFT JOIN
|    $Документ.ПриходныйОрдер as ДокПО ON ДокПО.IDDoc = Жур.IDDoc
|LEFT JOIN
|    $Документ.Отгрузка as ДокОтгр ON ДокОтгр.IDDoc = Жур.IDDoc
|WHERE
|    Жур.Date_Time_IDDoc BETWEEN :НачДата AND :КонДата~ AND
|    Жур.IDDocDef IN ($ВидДокумента.ПриходныйОрдер, $ВидДокумента.Отгрузка)
|";

В данном примере мы используем конструкцию CASE, чтобы определить вид документа. В зависимости от вида мы берем соответствующий 36-ричный префикс и прибавляем к нему ID объекта. Обратите внимание на типизацию колонки: AS [Отправитель $Справочник]. Теперь 1C++ получит строку из 13 символов, успешно ее распарсит и вернет в 1С полноценный объект (элемент справочника).

Важные нюансы и типизация «Любой тип»

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

  1. Длина строки: SQL Server может хранить данные в полях разной длины. Крайне важно, чтобы итоговая строка была ровно 13 символов. Если в базе данных поля имеют тип VARCHAR, рекомендуется использовать CAST(результат AS CHAR(13)), чтобы избежать проблем с «хвостами» или лишними пробелами.
  2. Пустые значения: Если CASE не срабатывает, лучше возвращать специальную константу пустого значения. В 1C++ это часто реализуется через 13 пробелов или макрос $ПустойИД13. Если вернуть просто пустую строку или NULL, типизация всей колонки может работать нестабильно.
  3. Тип «Любой»: Если в колонке могут быть не только разные справочники, но и, например, документы или перечисления, используйте типизацию AS [Поле $ТипЛюбой]. В этом случае к префиксу вида объекта (4 символа) нужно будет добавить еще и префикс самого метатипа.

Альтернативный метод: получение только наименований

Иногда нам не нужен сам объект 1С, а достаточно лишь вывести его текстовое представление (наименование). Это может быть полезно для ускорения работы отчета или если типизация вызывает сложности. Проанализируем, как это реализовать эффективно.

Для этого нам придется соединиться с таблицами справочников и выбрать поле DESCR. Посмотрим на пример реализации через дополнительные LEFT JOIN:


|SELECT
|    CASE Жур.IDDocDef
|        WHEN $ВидДокумента.ПриходныйОрдер THEN СпрКонтр.DESCR
|        WHEN $ВидДокумента.Отгрузка THEN СпрСклады.DESCR
|        ELSE ''
|    END AS ОтправительНаименование
|FROM
|    _1SJourn as Жур (nolock)
|LEFT JOIN
|    $Документ.ПриходныйОрдер as ДокПО ON ДокПО.IDDoc = Жур.IDDoc
|LEFT JOIN
|    $Справочник.Контрагенты as СпрКонтр ON СпрКонтр.ID = $ДокПО.Контрагент
|LEFT JOIN
|    $Документ.Отгрузка as ДокОтгр ON ДокОтгр.IDDoc = Жур.IDDoc
|LEFT JOIN
|    $Справочник.Склады as СпрСклады ON СпрСклады.ID = $ДокОтгр.Склад

Важный момент: При получении наименований всегда используйте ISNULL(..., ''). Если SQL встретит NULL при попытке отображения данных, это может привести к пустым ячейкам в результате всего отчета.

Оптимизация запроса

Использование множества LEFT JOIN и условий CASE в блоке SELECT может замедлять выполнение запроса на очень больших объемах данных. Рассмотрим вариант оптимизации через UNION ALL. Вместо того чтобы соединять всё в одном гигантском запросе, мы можем выполнить выборку по каждому виду документа отдельно и объединить результаты:


|SELECT 
|    $ДокПО.Контрагент as [Объект $Справочник.Контрагенты]
|FROM $Документ.ПриходныйОрдер as ДокПО
|
|UNION ALL
|
|SELECT 
|    $ДокОтгр.Склад as [Объект $Справочник.Склады]
|FROM $Документ.Отгрузка as ДокОтгр

Такой подход позволяет SQL-серверу строить более простые планы выполнения. Однако стоит помнить, что при использовании UNION ALL типы колонок должны быть совместимы. Для 1C++ это означает, что типизация должна быть приведена к общему виду, например, $Справочник или $ТипЛюбой, с добавлением тех самых префиксов $ВидСправочника36, которые мы разобрали выше.

Подведем итог: правильная типизация в 1С 7.7 требует понимания внутренней структуры ID. Используя $ВидСправочника36, вы сможете создавать гибкие и мощные отчеты, объединяющие данные из самых разных объектов метаданных.

← На главную