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

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

Работа с прямыми запросами в 1С:Предприятии 7.7 (через внешние компоненты, такие как 1C++ или Rainbow) требует от разработчика глубокого понимания структуры таблиц базы данных на уровне SQL-сервера. Одной из самых частых задач является выборка документов с определенным статусом: проведенные, непроведенные или помеченные на удаление. В стандартных объектных запросах 1С мы привыкли к простым флагам, но в SQL-таблице _1SJOURN (системный журнал документов) эти данные хранятся в виде битовых масок и числовых значений.

В данной статье мы разберем, почему возникают ошибки при фильтрации документов, проанализируем структуру системных полей и составим корректные запросы для различных бизнес-задач.

Разбор типичной логической ошибки

Рассмотрим ситуацию, с которой часто сталкиваются начинающие разработчики при написании условий в секции WHERE. Представим, что нам нужно выбрать одновременно и проведенные, и непроведенные документы, но исключить помеченные на удаление. Ошибочный код может выглядеть так:


|WHERE 
|    Журнал.CLOSED & 1 = 1
|AND Журнал.CLOSED & 1 = 0
|AND Журнал.ISMARK = 0

Проанализируем этот фрагмент. Оператор AND требует одновременного выполнения всех условий. Однако документ не может быть одновременно проведенным (CLOSED & 1 = 1) и непроведенным (CLOSED & 1 = 0). Это логическое противоречие, в результате которого SQL-сервер всегда будет возвращать пустой результат. Если нам нужны обе категории документов, использование фильтра по CLOSED в таком виде бессмысленно или требует оператора OR со скобками.

Поле CLOSED и работа с битовыми масками

В таблице _1SJOURN поле CLOSED является числовым и содержит в себе сразу несколько признаков состояния документа, упакованных в биты. Для извлечения нужного признака в SQL используется побитовое "И" (оператор &).

  1. Первый бит (значение 1): Отвечает за состояние "Проведен". Если результат выражения CLOSED & 1 равен 1, то документ проведен. Если 0 — не проведен.
  2. Второй бит (значение 2): Указывает на то, что документ делает движения по регистрам (активность).
  3. Третий бит (значение 4): Используется системой для внутренних нужд, например, при фиксации изменений в распределенных базах.

Выясним, как правильно составить условия:

Поле ISMARK: Пометка на удаление

Поле ISMARK отвечает за пометку документа на удаление. В SQL-версии 1С 7.7 это поле обычно имеет числовой тип (например, tinyint). Распространенная ошибка — попытка сравнить его с пустой строкой ISMARK = ''. Это приводит к некорректной работе запроса или его значительному замедлению, так как SQL-серверу приходится выполнять неявное преобразование типов для каждой строки таблицы.

Правильные значения для ISMARK:

Решение задачи №1: Проведенные + Непроведенные (но не удаленные)

Если ваша задача — получить список всех "живых" документов (и тех, что проведены, и тех, что просто записаны), то достаточно одного условия по полю ISMARK. Логика проста: если документ не помечен на удаление, он либо проведен, либо нет. Третьего не дано.


|WHERE 
|    Журнал.ISMARK = 0
|AND Журнал.iddocdef = $ВидДокумента.Реализация
|AND Журнал.date_time_iddoc BETWEEN :НачДата AND :КонДата~

В данном случае условие (CLOSED & 1 = 1) OR (CLOSED & 1 = 0) является избыточным (тавтологией), так как оно истинно для любой строки. Его исключение повысит производительность запроса.

Решение задачи №2: Только непроведенные и не помеченные на удаление

Иногда требуется найти "забытые" документы — те, которые были созданы, но не проведены и при этом не удалены. В этом случае мы объединяем два условия через оператор AND:


|WHERE 
|    Журнал.CLOSED & 1 = 0
|AND Журнал.ISMARK = 0
|AND Журнал.iddocdef = $ВидДокумента.Реализация

Здесь мы четко указываем SQL-серверу: "Выбери записи, где первый бит поля CLOSED равен нулю И флаг удаления равен нулю".

Оптимизация и индексы

Проанализируем, как SQL-сервер обрабатывает такие запросы. Таблица _1SJOURN в 1С 7.7 имеет критически важный индекс по полям IDDOCDEF и DATE_TIME_IDDOC. При написании прямого запроса крайне желательно придерживаться следующей структуры в блоке WHERE:

  1. Сначала указываем IDDOCDEF (вид документа), если выборка идет по конкретному типу.
  2. Затем указываем период через DATE_TIME_IDDOC.
  3. Только после этого добавляем фильтры по ISMARK, CLOSED и общим реквизитам.

Посмотрим на пример правильного структурированного запроса с использованием метасимволов 1C++:


ТекстЗапроса = "
|SELECT
|    Журнал.iddoc as [Док $Документ],
|    Журнал.iddocdef as Док_вид,
|    $Реализация.Контрагент as [Контрагент $Справочник.Контрагенты]
|FROM
|    _1SJOURN as Журнал
|INNER JOIN
|    $Документ.Реализация as Реализация ON Журнал.iddoc = Реализация.iddoc
|WHERE
|    Журнал.iddocdef = $ВидДокумента.Реализация
|    AND Журнал.date_time_iddoc BETWEEN :НачДата AND :КонДата~
|    AND Журнал.ISMARK = 0
|    AND $Реализация.Контрагент = :ВыбКонтрагент
|";

Важные замечания по синтаксису

Рассмотрим специфические моменты, которые помогут избежать ошибок:

1. Формат даты: Поле DATE_TIME_IDDOC в 1С 7.7 — это строка длиной 23 символа. Она содержит дату в формате YYYYMMDD, время и ID документа. Использование конструкции :НачДата и :КонДата~ в 1C++ автоматически преобразует объект даты 1С в нужный строковый формат SQL для правильного сравнения.

2. Скобки: Если вы все же решили использовать сложные условия с OR, всегда заключайте их в скобки. Например:

AND (Журнал.CLOSED & 1 = 0 OR Журнал.ISMARK = 1)

Без скобок приоритет оператора AND может нарушить логику всего запроса, и вы получите непредсказуемый результат.

3. Типы данных: Помните, что $ОбщийРеквизит.Фирма и подобные конструкции разворачиваются в названия полей SQL. Если реквизит имеет тип "Справочник", сравнение должно идти с ID (строкой из 9 символов), а не с наименованием или объектом.

Итоги

Мы выяснили, что для корректной работы с документами через прямые запросы необходимо:

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

← На главную