В практике разработчика и аналитика 1С часто встречается ситуация: в виртуальной таблице остатков регистра накопления висят две строки, которые в сумме дают ноль. Визуально все измерения — Организация, Сотрудник, Статья расходов — кажутся идентичными, но платформа упорно отказывается «сворачивать» их в одну нулевую запись. Проанализируем, почему это происходит, и разберем по шагам методы диагностики этой проблемы.
Для начала вспомним, как работает платформа 1С:Предприятие 8. Виртуальная таблица Остатки формируется на лету на основании физической таблицы итогов или движений. Платформа группирует записи по всем измерениям регистра. Если хотя бы одно поле в базе данных отличается хотя бы на один бит, СУБД (будь то MS SQL или PostgreSQL) воспримет их как разные записи, и группировка не произойдет.
Рассмотрим подробнее основные причины, по которым измерения могут казаться одинаковыми, но быть разными на уровне данных:
УникальныйИдентификатор (GUID).ДокументОснование) значение может быть не заполнено, но технически в одном случае это будет Неопределено, а в другом — пустая ссылка конкретного типа.Если мы видим в отчете двух одинаковых сотрудников, первым делом нужно убедиться, что это один и тот же объект в базе данных. Простой запрос к виртуальной таблице остатков с выводом ссылок часто не помогает, так как ссылки визуально одинаковы. Проанализируем ситуацию, используя функцию получения уникального идентификатора.
Напишем запрос, который выведет идентификаторы для подозрительных измерений:
ВЫБРАТЬ
ЗарплатаКВыплатеОстатки.Сотрудник КАК Сотрудник,
ЗарплатаКВыплатеОстатки.Сотрудник.УникальныйИдентификатор() КАК СотрудникGUID,
ЗарплатаКВыплатеОстатки.СуммаВзаиморасчетовОстаток КАК Остаток
ИЗ
РегистрНакопления.ЗарплатаКВыплате.Остатки КАК ЗарплатаКВыплатеОстатки
Если в результате запроса мы увидим разные значения в колонке СотрудникGUID при одинаковых именах, значит, в справочнике есть дубли. В системе ЗУП это часто случается, когда создаются разные карточки сотрудников для одного и того же физического лица (например, при внутреннем совместительстве).
Одной из самых коварных проблем является различие типов в пустых значениях. Рассмотрим измерение ДокументОснование в регистре «Зарплата к выплате». Это измерение имеет составной тип. Если одна запись была сделана документом, который не заполнил это измерение (значение Неопределено), а вторая запись была сделана «Переносом данных», где была выбрана пустая ссылка конкретного типа документа, они не схлопнутся.
Выясним причину, используя функцию ТИПЗНАЧЕНИЯ в консоли запросов:
ВЫБРАТЬ
ТИПЗНАЧЕНИЯ(ЗарплатаКВыплатеОстатки.ДокументОснование) КАК ТипДокумента,
ЗарплатаКВыплатеОстатки.ДокументОснование КАК ЗначениеДокумента,
ЗарплатаКВыплатеОстатки.СуммаВзаиморасчетовОстаток КАК Остаток
ИЗ
РегистрНакопления.ЗарплатаКВыплате.Остатки КАК ЗарплатаКВыплатеОстатки
В результате мы можем увидеть следующую картину: в одной строке тип будет NULL или Неопределено, а во второй — Документ.НачислениеЗарплаты. Для платформы это фундаментально разные данные, несмотря на то, что в колонке «Значение» в обоих случаях будет пусто.
Когда работа с виртуальной таблицей остатков не дает ответа, нужно проанализировать «первоисточник» — физическую таблицу регистра. Это позволит увидеть, какие именно документы (регистраторы) создали эти записи и в какие периоды.
Рассмотрим пример запроса к основной таблице регистра:
ВЫБРАТЬ
ЗарплатаКВыплате.Период КАК Период,
ЗарплатаКВыплате.Регистратор КАК Регистратор,
ЗарплатаКВыплате.ВидДвижения КАК ВидДвижения,
ЗарплатаКВыплате.Сотрудник КАК Сотрудник,
ЗарплатаКВыплате.СуммаВзаиморасчетов КАК Сумма
ИЗ
РегистрНакопления.ЗарплатаКВыплате КАК ЗарплатаКВыплате
ГДЕ
ЗарплатаКВыплате.Сотрудник = &Сотрудник
И ЗарплатаКВыплате.Организация = &Организация
Проанализируем результаты. Особое внимание уделим колонке ВидДвижения. Иногда пользователи пытаются «обнулить» остаток, вводя запись с тем же знаком, но противоположным видом движения (например, вместо «Расход 30» вводят «Приход -30»). Хотя математически это дает ноль, технически в регистре остатков такие записи могут вести себя некорректно в зависимости от настроек конфигурации.
Как показывает практика разбора сложных случаев в ЗУП 3.1, часто проблема кроется в документе Начальная задолженность. Этот документ специфичен тем, что он может оставлять измерение ДокументОснование действительно пустым (тип Неопределено). В то же время универсальный документ Перенос данных при попытке очистить поле составного типа часто подставляет туда пустую ссылку первого доступного типа из списка метаданных.
Важный момент: если вы пытаетесь схлопнуть остаток, созданный Начальной задолженностью, с помощью Переноса данных, убедитесь, что в Переносе данных поле Документ-основание очищено полностью (клавишей Shift+F4), чтобы там установилось значение Неопределено, а не пустая ссылка на какой-нибудь «Больничный лист».
Если запросы показывают абсолютную идентичность всех полей, включая типы и ГУИДы, но остаток все равно двоится, возможно повреждение таблицы итогов. Это случается при аварийном завершении работы сервера или сбоях СУБД.
Рассмотрим шаги по исправлению:
_AccumRegTotals в SQL) и заполнит их заново на основе таблицы движений.Подведем итог. Чтобы «схлопнуть» зависшие строки, выполним последовательность действий:
УникальныйИдентификатор().ТИПЗНАЧЕНИЯ().Перенос данных) установлены те же самые значения, включая «невидимые» различия между Неопределено и пустой ссылкой.Помните, что регистр накопления в 1С — это строгая математическая модель. Если записи не соединяются, значит, между ними есть хотя бы минимальное техническое различие, которое нужно локализовать с помощью консоли запросов.