Как в прямом SQL-запросе 1С 7.7 получить периодический реквизит справочника через цепочку связей

Программист 1С v7.7 Управленческий учет
← На главную

При работе с прямыми запросами в 1С 7.7 (с использованием внешней компоненты 1С++) программисты часто сталкиваются с необходимостью получения данных, которые находятся «через несколько точек» от основного объекта. Ситуация осложняется, когда целевой реквизит является периодическим. В «черных» (стандартных) запросах 1С система берет на себя всю работу по поиску актуального значения на нужную дату, но в SQL нам приходится прописывать эту логику самостоятельно.

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

Исходная задача и структура запроса

Представим ситуацию: нам нужно сформировать отчет по различным типам документов (Реализация, ЗаявкаПокупателя, КоммПредложение, СтрокаВыпискиПриход). Для каждого документа необходимо получить контрагента и его менеджера (реквизит ВашМенеджер справочника Проекты), причем менеджер является периодическим реквизитом справочника Контрагенты.

Рассмотрим структуру базового запроса к таблице журнала документов _1SJOURN. Для объединения данных из разных типов документов мы будем использовать LEFT JOIN к каждой таблице документа и функцию COALESCE для выбора первого непустого значения контрагента.


SELECT 
    Журнал.IDDoc AS [ТекДок $Документ],
    Журнал.IDDocDef AS ТекДок_вид,
    coalesce($Реализация.Контрагент, $ЗаявкаПокупателя.Контрагент, $КоммПредложение.Контрагент, $СтрокаВыпискиПриход.Контрагент) AS [Контрагент $Справочник.Контрагенты]
FROM 
    _1SJOURN AS Журнал With (NOLOCK)
LEFT JOIN 
    $Документ.Реализация AS Реализация With (NOLOCK) ON Журнал.IDDOC = Реализация.IDDOC
LEFT JOIN 
    $Документ.ЗаявкаПокупателя AS ЗаявкаПокупателя With (NOLOCK) ON Журнал.IDDOC = ЗаявкаПокупателя.IDDOC
-- Дополнительные LEFT JOIN для других документов...
WHERE 
    Журнал.date_time_iddoc between :НачДата and :КонДата~

Проблема периодических реквизитов в SQL

Если бы реквизит ВашМенеджер был обычным (не периодическим), мы бы просто добавили еще один LEFT JOIN к таблице $Справочник.Контрагенты и обратились бы к полю $Контрагенты.ВашМенеджер. Однако периодические значения в 1С 7.7 хранятся не в основной таблице справочника, а в общей таблице _1SCONST. Прямое обращение к ней требует написания сложных подзапросов для поиска значения, актуального на конкретную дату (с учетом времени и позиции документа).

К счастью, компонента 1С++ предоставляет мощный инструмент — макрос $ПоследнееЗначение, который автоматизирует генерацию подзапроса к таблице констант.

Решение через макрос $ПоследнееЗначение

Проанализируем правильный синтаксис получения периодического реквизита. Нам нужно получить ID менеджера из справочника Контрагенты. Мы можем сделать это прямо в блоке SELECT или в условии связи JOIN.

Рассмотрим по шагам, как добавить получение менеджера для документа Реализация:

  1. Определяем идентификатор контрагента из таблицы документа.
  2. Используем макрос $ПоследнееЗначение, передавая в него имя справочника, имя реквизита, ID объекта (контрагента) и дату, на которую нужно получить значение.

Пример реализации в составе общего запроса:


SELECT 
    Журнал.IDDoc AS [ТекДок $Документ],
    $Реализация.Контрагент AS [Контрагент $Справочник.Контрагенты],
    -- Получаем ID менеджера через макрос
    ($ПоследнееЗначение.Контрагенты.ВашМенеджер($Реализация.Контрагент, :КонДата)) AS [Менеджер $Справочник.Проекты]
FROM 
    _1SJOURN AS Журнал With (NOLOCK)
LEFT JOIN 
    $Документ.Реализация AS Реализация With (NOLOCK) ON Реализация.IDDOC = Журнал.IDDOC
WHERE 
    Журнал.iddocdef = $ВидДокумента.Реализация
    AND Журнал.date_time_iddoc between :НачДата and :КонДата~

В данном примере :КонДата — это параметр запроса (дата конца периода). Если нам нужно получить менеджера, который был закреплен за контрагентом на момент создания документа, вместо фиксированной даты следует использовать поле журнала Журнал.date_time_iddoc.

Оптимизация и работа через COALESCE

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

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


SELECT 
    Журнал.IDDoc AS [ТекДок $Документ],
    Журнал.IDDocDef AS ТекДок_вид,
    -- Собираем контрагента из разных таблиц
    coalesce($Реализация.Контрагент, $ЗаявкаПокупателя.Контрагент, $КоммПредложение.Контрагент) AS КонтрИд,
    -- Получаем периодический реквизит для найденного контрагента
    ($ПоследнееЗначение.Контрагенты.ВашМенеджер(
        coalesce($Реализация.Контрагент, $ЗаявкаПокупателя.Контрагент, $КоммПредложение.Контрагент), 
        :КонДата
    )) AS [ВашМенеджер $Справочник.Проекты]
FROM 
    _1SJOURN AS Журнал With (NOLOCK)
LEFT JOIN $Документ.Реализация AS Реализация With (NOLOCK) ON Журнал.IDDOC = Реализация.IDDOC
LEFT JOIN $Документ.ЗаявкаПокупателя AS ЗаявкаПокупателя With (NOLOCK) ON Журнал.IDDOC = ЗаявкаПокупателя.IDDOC
-- ... остальные соединения

Важные нюансы использования

Разберем несколько критических моментов, которые помогут избежать пустых значений в результате:

Таким образом, прямой запрос позволяет гибко управлять получением данных, предоставляя производительность, недоступную штатным средствам 1С 7.7, при условии правильного использования механизмов 1С++.

← На главную