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

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

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

В данной статье мы разберем, как правильно спроектировать такой запрос, проанализируем типичные ошибки при использовании UNION ALL и выясним, как оптимизировать работу с метапарсером 1С++.

Ограничение виртуальных таблиц и выбор стратегии

Рассмотрим ситуацию: нам необходимо получить начальный остаток на каждый день, приход и расход в разрезе документов, и конечный остаток. Если мы укажем периодичность Документ в виртуальной таблице $РегистрОстаткиОбороты, мы получим детальные движения, но не увидим остатки на те дни, когда движений не было. Если выберем День — потеряем информацию о том, какой именно документ совершил оборот.

Для решения этой задачи мы можем использовать несколько подходов:

  1. Объединение (UNION ALL) результатов запроса к таблице остатков (на начало периода) и запроса к таблице движений (обороты).
  2. Использование класса «ПоставщикДанных», который инкапсулирует логику дополнения периодов.
  3. Прямое обращение к физическим таблицам регистра (_1SRA) и журнала документов (_1SJOURN).

Реализация через UNION ALL и типичные ошибки метапарсера

Проанализируем пример, где нам нужно объединить данные по разным видам документов (например, «ВыпускБР» и «ВыпускБРЗапуска»). Часто программисты пытаются использовать одинаковые алиасы для таблиц документов в разных частях объединения, что приводит к ошибке SQL State 42S22 (недопустимое имя столбца).

Разберем, почему это происходит. Метапарсер 1С++ работает по принципу подстановки: когда он встречает конструкцию $Документ.ВыпускБР AS Док, он запоминает, что алиас Док соответствует конкретной таблице. Если во второй части UNION вы снова пишете $Документ.ВыпускБРзапуска AS Док, парсер может некорректно сопоставить имена полей (например, реквизит БР в первой таблице имеет физическое имя sp13482, а во второй — другое). SQL-сервер не найдет поле из первой таблицы во второй.

Рассмотрим правильный пример написания такого запроса с использованием уникальных алиасов и корректной типизацией:


|SELECT
|   Журнал.IDDOCDEF [Док_вид $ВидДокумента],
|   Журнал.IDDOC [Док $Документ],
|   $Док1.БР as [Товар $Справочник.ТМЦ],
|   Sum($ДокС1.ПоФакту) as Количество
|FROM 
|   _1SJOURN AS Журнал
|INNER JOIN $Документ.ВыпускБР AS Док1 ON Журнал.IDDOC = Док1.IDDOC
|INNER JOIN $ДокументСтроки.ВыпускБР AS ДокС1 ON Док1.IDDOC = ДокС1.IDDOC
|WHERE Журнал.DATE_TIME_IDDOC BETWEEN :НачДата AND :КонДата~
|
|UNION ALL
|
|SELECT
|   Журнал.IDDOCDEF,
|   Журнал.IDDOC,
|   $Док2.БР,
|   Sum($ДокС2.ПоФакту)
|FROM 
|   _1SJOURN AS Журнал
|INNER JOIN $Документ.ВыпускБРзапуска AS Док2 ON Журнал.IDDOC = Док2.IDDOC
|INNER JOIN $ДокументСтроки.ВыпускБРзапуска AS ДокС2 ON Док2.IDDOC = ДокС2.IDDOC
|WHERE Журнал.DATE_TIME_IDDOC BETWEEN :НачДата AND :КонДата~
|GROUP BY Журнал.IDDOCDEF, Журнал.IDDOC, $Док1.БР, $Док2.БР -- упрощенно

Важный нюанс: Обратите внимание, что типизация (конструкции вида [Имя $Тип]) указывается только в первом запросе блока UNION ALL. SQL-сервер определяет структуру результирующего набора по первому SELECT. Последующие блоки должны просто возвращать данные в столбцы тех же типов и в том же порядке.

Оптимизация: Использование таблицы движений регистра

Если в конфигурации включена опция «Быстрая обработка движений» для регистра, то информация о дате и виде документа дублируется в таблицу движений регистра (физическая таблица _1SRA). В этом случае нам не нужно соединяться с таблицей _1SJOURN (Журнал документов), что существенно ускоряет запрос.

Проанализируем ситуацию, когда нам нужны только обороты в разрезе видов документов. Мы можем напрямую фильтровать по полю IDDOCDEF:


|SELECT
|   Reg.IDDOCDEF [ВидДок $ВидДокумента],
|   Reg.IDDOC [Док $Документ],
|   $Reg.Товар [Товар $Справочник.ТМЦ],
|   $Reg.Количество as Расход
|FROM
|   $Регистр.ОперСклады AS Reg
|WHERE
|   Reg.DATE_TIME_IDDOC BETWEEN :НачДата AND :КонДата~
|   AND Reg.IDDOCDEF = $ВидДокумента.ВыпускБР

Это самый быстрый способ выборки данных. Однако помните, что если вам нужны именно остатки на каждый день, использование только таблицы движений недостаточно — необходимо будет программно или средствами SQL вычислять накопительный итог от начального остатка.

Работа с датами и условиями в прямых запросах

При работе с журналом документов _1SJOURN ключевым полем для фильтрации по времени является DATE_TIME_IDDOC. Оно содержит в себе дату, время и уникальный идентификатор документа. Выясним причину, почему использование BETWEEN с символом тильды ~ является предпочтительным.

Конструкция :КонДата~ в 1С++ автоматически преобразует дату в конец дня (добавляет время 23:59:59), что позволяет корректно захватить документы, созданные в последнюю секунду указанного периода. Без этого символа запрос может пропустить документы, созданные внутри дня КонДата.

Также стоит избегать условий вида Журнал.Closed & 1 = 1 для проверки проведенности документа, если это возможно. Побитовые операции в секции WHERE могут блокировать использование индексов SQL-сервером, что приведет к полному сканированию таблицы (Table Scan) вместо быстрого поиска (Index Seek).

Использование класса «ПоставщикДанных»

Для тех, кто хочет получить функционал, максимально приближенный к системе компоновки данных (СКД) в 1С 8, рекомендуется использовать класс ПоставщикДанных. Он позволяет строить запросы с дополнение периодов «на каждый день» автоматически. Рассмотрим основные преимущества этого подхода:

Подводя итог, можно сказать: построение прямого запроса по дате и документам в 1С 7.7 требует четкого понимания работы метапарсера. Используйте уникальные алиасы для разных таблиц в UNION, выносите типизацию в первый SELECT и отдавайте предпочтение таблицам движений регистра, если включена быстрая обработка. Это позволит вашим отчетам работать в десятки раз быстрее стандартных средств 1С.

← На главную