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

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

При выполнении прямых SQL-запросов к базе данных 1С:Предприятие 7.7 разработчики часто сталкиваются с ситуацией, когда простая инструкция UPDATE не находит нужные строки или некорректно очищает реквизиты ссылочного типа. Выясним причину такого поведения и разберем по шагам, как устроено хранение ссылок на документы в SQL-таблицах платформы 1С 7.7, а также рассмотрим рабочие способы решения этой задачи.

В чем заключается проблема хранения составных типов в 1С 7.7

Разберем механику хранения ссылочных данных в SQL-базе 1С 7.7. Формат поля в таблице базы данных (например, в таблицах шапки документов DH*) напрямую зависит от того, задан ли конкретный вид документа у реквизита или установлен неопределенный тип:

  1. Конкретный тип документа: если в конфигураторе у реквизита явно указан вид (например, Документ.РасходнаяБН), в базе SQL он хранится в виде строки длиною 9 символов (CHAR(9)), содержащей уникальный идентификатор документа IDDOC.
  2. Неопределенный тип (тип «Документ»): если реквизит может принимать значение любого документа в системе, платформа выделяет под него строку длиною 13 символов (CHAR(13)). В этих 13 символах зашифрована составная ссылка: первые 4 символа содержат код вида документа в 36-ричной системе счисления (Base36), а следующие 9 символов — непосредственно IDDOC.

Когда мы пытаемся выполнить сравнение реквизита неопределенного типа с обычным 9-символьным значением IDDOC или присвоить ему макрос $ПустойИД (который возвращает 9 символов), СУБД сравнит строки разной длины и запрос либо не вернет строк для обновления, либо запишет битые данные.

Решение проблемы через прямой SQL-запрос (1С++)

Чтобы корректно отфильтровать и очистить реквизит неопределенного типа «Документ» через прямой SQL-запрос с использованием внешней компоненты 1С++, необходимо сформировать 13-символьное значение ссылки, состоящее из кода вида документа в Base36 и его IDDOC.

Рассмотрим рабочий пример SQL-запроса, в котором очищается реквизит ДокументПолнойОплаты в документе РасходнаяБН:


Текст = "
    |UPDATE Накладная
    |SET 
    |    $Накладная.ДокументПолнойОплаты = $ПустойИД
    |FROM $Документ.РасходнаяБН AS Накладная
    |INNER JOIN _1sjourn AS журнал ON журнал.iddoc = :Документ
    |WHERE $Накладная.ДокументПолнойОплаты = $ВидДокумента36." + ПДНС.Вид() + " + журнал.iddoc";

Проанализируем ключевые моменты этого запроса:

  1. Макрос $ВидДокумента36.ИмяВида автоматически подставляет 4-символьный префикс вида документа в кодировке Base36.
  2. Конкатенация $ВидДокумента36.Вид + журнал.iddoc дает полные 13 символов, с которыми корректно сравнивается реквизит неопределенного типа.
  3. Для очистки конкретного поля в зависимости от настроек ВК 1С++ и типа поля используется сброс в пустое значение. При работе со строго 13-символьными полями также применяется специализированный макрос $ПустойИД13 или строка из 13 пробелов.

Важные риски и особенности прямого UPDATE

Проводя прямые изменения в SQL-таблицах платформы 1С 7.7, необходимо учитывать архитектурные ограничения:

  1. Таблица подчиненности (_1scrdoc): прямой UPDATE таблицы шапки документа (DH*) не изменяет системную таблицу связей _1scrdoc. Если очищаемый реквизит участвует в структуре подчиненности, документ продолжит отображаться в дереве подчиненных документов до выполнения операции «Пересчет служебных данных» в процессе «Тестирование и исправление информационной базы».
  2. Кэширование на клиентах: активные сеансы пользователей кэшируют данные в памяти. Если документ открыт у пользователя в момент выполнения SQL-запроса, при последующей интерактивной записи из формы старые данные из кэша перезапишут изменения в базе данных.

Альтернативный штатный способ без перепроведения

Если задача заключается в том, чтобы изменить реквизиты шапки без повторного формирования движений по регистрам и без риска нарушить целостность _1scrdoc, рекомендуется использовать штатные средства языка 1С 7.7.

Метод Записать() обновляет реквизиты документа и структуру подчиненности, сбрасывает кэш и не вызывает процедуру ОбработкаПроведения():


Док = СоздатьОбъект("Документ.РасходнаяБН");
Если Док.НайтиДокумент(НужныйДокумент) = 1 Тогда
    Док.ДокументПолнойОплаты = ПолучитьПустоеЗначение("Документ");
    Док.Записать(); // Обновляет реквизиты шапки и таблицу связей, не меняя движения
КонецЕсли;

Этот подход гарантирует полное соответствие логике 1С:Предприятие 7.7 и исключает необходимость проведения тестирования и исправления базы данных.

← На главную