При выполнении процедуры закрытия месяца в конфигурациях «1С:Управление торговлей 11» (а также в «1С:ERP» и «1С:Комплексная автоматизация») пользователи и разработчики нередко сталкиваются с ситуацией, когда регламентный этап «Исправление отрицательных остатков организации» остается в незавершенном статусе. При этом запуск стандартной обработки исправления сообщает, что отрицательных остатков не обнаружено, однако этап закрытия месяца все равно висит как невыполненный.
Разберем детально механизм возникновения этой проблемы, проанализируем поведение оптимизатора запросов платформы и СУБД, а также рассмотрим пошаговые способы устранения ошибки.
Посмотрим на типовой запрос, который используется платформой для определения статуса необходимости этапа исправления остатков:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Остатки.ЕстьОтрицательныеОстатки
ИЗ (
ВЫБРАТЬ
ИСТИНА КАК ЕстьОтрицательныеОстатки,
Остатки.Организация,
Остатки.АналитикаУчетаНоменклатуры,
Остатки.ВидЗапасов,
Остатки.НомерГТД
ИЗ
РегистрНакопления.ТоварыОрганизаций.Остатки(&Граница, Организация В (&МассивОрганизаций)) КАК Остатки
ГДЕ
Остатки.КоличествоОстаток < 0
) КАК Остатки
При выполнении этого запроса в консоли, даже если реальных движений с отрицательными значениями в базе нет, запрос может возвращать ровно одну строку со значением NULL в поле ЕстьОтрицательныеОстатки. Если же переписать запрос, заменив выборку поля на ВЫБРАТЬ РАЗЛИЧНЫЕ *, результат становится полностью пустым (0 строк).
Выясним причины такого поведения:
_AccumReg) и таблиц итогов (_AccumRegTotals). Когда во внешнем запросе выбирается конструкция ВЫБРАТЬ РАЗЛИЧНЫЕ только для поля-константы (ИСТИНА), оптимизатор платформы и SQL-сервера может свернуть выборку до скалярного агрегата над внешним соединением. В результате возвращается одна строка со значением NULL.ТоварыОрганизаций могут содержать фантомные записи или некорректные даты среза итогов.NULL.Если проблема вызвана повреждением или рассинхронизацией таблиц итогов после переноса данных, наиболее надежный способ — выполнить обслуживание базы средствами конфигуратора. Разберем порядок действий:
После реиндексации и пересчета итогов виртуальные таблицы регистра ТоварыОрганизаций перестроятся на стороне СУБД, и ложное срабатывание запроса закрытия месяца будет устранено.
Если база данных имеет большой объем и полное тестирование займет слишком много времени, выполним пересчет итогов точечно только для регистра ТоварыОрганизаций во внешней обработке или через консоль кода:
// Устанавливаем признак использования итогов и принудительно пересчитываем их
РегистрыНакопления.ТоварыОрганизаций.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.ТоварыОрганизаций.ПересчитатьИтоги();
Данный метод обновляет системные таблицы итогов конкретного регистра без блокировки всей информационной базы.
Если мы дорабатываем алгоритмы проверки остатков в собственных отчетах или процедурах закрытия, откажемся от вложенных запросов с константами в пользу прямой и однозначной конструкции выборки:
ВЫБРАТЬ ПЕРВЫЕ 1
1 КАК ЕстьОтрицательныеОстатки
ИЗ
РегистрНакопления.ТоварыОрганизаций.Остатки(
&Граница,
Организация В (&МассивОрганизаций)
) КАК Остатки
ГДЕ
Остатки.КоличествоОстаток < 0
В коде встроенного языка 1С проверку факта наличия отрицательных остатков следует выполнять через проверку выборки, не завязываясь на значение поля:
УстановитьПривилегированныйРежим(Истина);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
// Обнаружены отрицательные остатки
КонецЕсли;
Использование метода УстановитьПривилегированныйРежим(Истина) позволяет исключить влияние ограничений прав доступа (RLS), гарантируя корректность возвращаемого результата.