Перевод стандартных запросов 1С 7.7 на прямые SQL-запросы с использованием внешней компоненты 1С++ — это отличный способ ускорить работу системы в 10 раз и более. Однако при работе с документами разных видов программисты часто сталкиваются с проблемой фильтрации данных по списку значений. В этой статье мы подробно разберем, как правильно передать «разношерстный» список документов в SQL-запрос, проанализируем структуру идентификаторов и выберем оптимальную стратегию построения запроса.
Представим ситуацию: у нас есть СписокЗначений, в который программно отобраны документы разных видов (например, «ПочтовоеОтправление» и «КоммерческоеПредложение»). Нам необходимо выбрать данные из базы, ограничив выборку только теми документами, которые присутствуют в этом списке. Чтобы лучше понимать, как хранятся данные, рекомендуется изучить анализ объектов метаданных для конфигураций 1С 7.7, где описана структура таблиц. Основная сложность заключается в том, что в 1С 7.7 идентификатор объекта может быть представлен в двух форматах: коротком (9 символов) и длинном (13 символов).
Разберем, как устроены эти идентификаторы:
_1SJOURN. Важно помнить, что в 1С 7.7 IDDOC глобально уникален — не бывает двух документов разных видов с одинаковым IDDOC.IDDOCDEF (идентификатор вида документа в 36-ричной системе) и 9 символов IDDOC.Если нам нужно просто отфильтровать документы по их уникальному внутреннему коду, мы можем воспользоваться методом УложитьСписокОбъектов, который предоставляют расширения запросов 1С++. Рассмотрим пример кода на языке 1С, который подготавливает временную таблицу в SQL:
// Создаем объект запроса 1С++
Запрос = СоздатьОбъект("УдаленныйЗапрос");
// СписокДокументов - это наш СписокЗначений с разными документами
Запрос.УложитьСписокОбъектов(СписокДокументов, "#СЗКонтакты");
В данном случае третий параметр (тип объекта) указывать не нужно. Для документов он игнорируется, так как IDDOC самодостаточен. В базе SQL будет создана временная таблица #СЗКонтакты с колонкой val, содержащей 9-символьные идентификаторы. Проанализируем, как будет выглядеть условие в самом SQL-запросе, используя консоль запросов для отладки:
SELECT
Журнал.IDDOC [Документ $Документ],
Журнал.IDDOCDEF Документ_вид
FROM
_1SJOURN AS Журнал
WHERE
Журнал.IDDOC IN (SELECT val FROM #СЗКонтакты)
В ситуациях, когда вы работаете с составными типами данных или когда нужно гарантировать точное совпадение вида и идентификатора (например, при соединении по виртуальным полям $ВидДокумента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, делая отдельный 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. Мы можем преобразовать ссылку 1С в строковый идентификатор базы данных вручную, по аналогии с тем, как реализована универсальная функция отбора в справочниках по строковым реквизитам.
Рассмотрим пример использования:
Мета = СоздатьОбъект("MetaDataWork");
ТекДок = СписокДокументов.ПолучитьЗначение(1);
// Получаем 13-символьную строку
СтрБД = Мета.ЗначениеВСтрокуБД(ТекДок);
// В запросе можно использовать:
// WHERE $ВидДокумента36.МойВид + IDDOC = :ВыбДок
Запрос.УстановитьТекстовыйПараметр("ВыбДок", СтрБД);
Для эффективной фильтрации по списку документов разных видов в 1С 7.7 мы рекомендуем придерживаться следующих правил:
IDDOC в журнале, достаточно обычного метода УложитьСписокОбъектов без указания типа.УложитьСписокОбъектов13.UNION ALL, если данные можно получить через LEFT JOIN от таблицы _1SJOURN.$ВидДокумента36.Имя, который возвращает строковый идентификатор вида, необходимый для конкатенации ссылок.Использование этих техник позволит вам создавать быстрые и надежные отчеты, которые справятся с любыми объемами данных в старых конфигурациях 1С 7.7.