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

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

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

Постановка задачи и анализ структуры данных

Представим ситуацию: у нас есть СписокЗначений, в который программно отобраны документы разных видов (например, «ПочтовоеОтправление» и «КоммерческоеПредложение»). Нам необходимо выбрать данные из базы, ограничив выборку только теми документами, которые присутствуют в этом списке. Чтобы лучше понимать, как хранятся данные, рекомендуется изучить анализ объектов метаданных для конфигураций 1С 7.7, где описана структура таблиц. Основная сложность заключается в том, что в 1С 7.7 идентификатор объекта может быть представлен в двух форматах: коротком (9 символов) и длинном (13 символов).

Разберем, как устроены эти идентификаторы:

  1. IDDOC (9 символов): Это уникальный идентификатор документа в рамках всей базы данных. Он хранится в таблице общего журнала _1SJOURN. Важно помнить, что в 1С 7.7 IDDOC глобально уникален — не бывает двух документов разных видов с одинаковым IDDOC.
  2. Полный идентификатор (13 символов): Используется для типизации «неопределенных» реквизитов. Он состоит из 4 символов IDDOCDEF (идентификатор вида документа в 36-ричной системе) и 9 символов IDDOC.

Метод 1: Использование УложитьСписокОбъектов

Если нам нужно просто отфильтровать документы по их уникальному внутреннему коду, мы можем воспользоваться методом УложитьСписокОбъектов, который предоставляют расширения запросов 1С++. Рассмотрим пример кода на языке 1С, который подготавливает временную таблицу в SQL:


// Создаем объект запроса 1С++
Запрос = СоздатьОбъект("УдаленныйЗапрос");
// СписокДокументов - это наш СписокЗначений с разными документами
Запрос.УложитьСписокОбъектов(СписокДокументов, "#СЗКонтакты");

В данном случае третий параметр (тип объекта) указывать не нужно. Для документов он игнорируется, так как IDDOC самодостаточен. В базе SQL будет создана временная таблица #СЗКонтакты с колонкой val, содержащей 9-символьные идентификаторы. Проанализируем, как будет выглядеть условие в самом SQL-запросе, используя консоль запросов для отладки:


SELECT
    Журнал.IDDOC [Документ $Документ],
    Журнал.IDDOCDEF Документ_вид
FROM
    _1SJOURN AS Журнал
WHERE
    Журнал.IDDOC IN (SELECT val FROM #СЗКонтакты)

Метод 2: Использование УложитьСписокОбъектов13 для сложных случаев

В ситуациях, когда вы работаете с составными типами данных или когда нужно гарантировать точное совпадение вида и идентификатора (например, при соединении по виртуальным полям $ВидДокумента36 + IDDOC), лучше использовать метод УложитьСписокОбъектов13. Этот метод принудительно приводит все элементы списка к 13-символьному виду.

Рассмотрим, как это реализовать в коде:


// Укладываем список в 13-символьном формате
Запрос.УложитьСписокОбъектов13(СписокДокументов, "#СЗДокументы13");

ТекстЗапроса = "
|SELECT
|    $ВидДокумента36.я_ПочтовоеОтправление + Журнал.IDDOC [Ссылка $Документ]
|FROM
|    _1SJOURN AS Журнал
|WHERE
|    $ВидДокумента36.я_ПочтовоеОтправление + Журнал.IDDOC IN (SELECT val FROM #СЗДокументы13)
|";

Этот подход более универсален, если в вашем запросе используются конструкции объединения UNION ALL, где вы вручную формируете ссылки.

Оптимизация: Отказ от UNION ALL в пользу общего журнала

Часто программисты пытаются собрать данные по разным видам документов через UNION ALL, делая отдельный SELECT к каждой таблице документа (например, $Документ.я_Контакт). Это может привести к громоздкому коду. Проанализируем альтернативный путь — использование таблицы _1SJOURN как базовой, что часто применяет обработка для просмотра данных и анализа структуры 1С 7.7.

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

Посмотрим на пример оптимизированного запроса:


SELECT
    Жур.IDDOC [Элемент $Документ],
    COALESCE($ДокКонтакт.Контрагент, $ДокПредложение.Контрагент) [Контрагент $Справочник.Контрагенты],
    Жур.DATE_TIME_IDDOC Дата
FROM
    _1SJOURN AS Жур With (NOLOCK)
LEFT JOIN
    $Документ.я_Контакт AS ДокКонтакт ON ДокКонтакт.IDDOC = Жур.IDDOC
    AND Жур.IDDOCDEF = $ВидДокумента.я_Контакт
LEFT JOIN
    $Документ.я_КоммерческоеПредложение AS ДокПредложение ON ДокПредложение.IDDOC = Жур.IDDOC
    AND Жур.IDDOCDEF = $ВидДокумента.я_КоммерческоеПредложение
WHERE
    Жур.IDDOC IN (SELECT val FROM #СЗКонтакты)
    AND Жур.ISMARK = 0

Работа с MetaDataWork для ручного формирования условий

Иногда требуется сформировать текст запроса динамически, не прибегая к временным таблицам (хотя это и менее эффективно). В этом нам поможет объект MetaDataWork. Мы можем преобразовать ссылку 1С в строковый идентификатор базы данных вручную, по аналогии с тем, как реализована универсальная функция отбора в справочниках по строковым реквизитам.

Рассмотрим пример использования:


Мета = СоздатьОбъект("MetaDataWork");
ТекДок = СписокДокументов.ПолучитьЗначение(1);

// Получаем 13-символьную строку
СтрБД = Мета.ЗначениеВСтрокуБД(ТекДок);

// В запросе можно использовать:
// WHERE $ВидДокумента36.МойВид + IDDOC = :ВыбДок
Запрос.УстановитьТекстовыйПараметр("ВыбДок", СтрБД);

Подводим итоги

Для эффективной фильтрации по списку документов разных видов в 1С 7.7 мы рекомендуем придерживаться следующих правил:

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

← На главную