Почему дублируются строки в запросе к виртуальной таблице остатков 1С?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

Разбор основной ошибки: Декартово произведение

Рассмотрим ситуацию, в которой разработчик пытается получить остатки по сотрудникам, но при этом хочет видеть данные за определенный период. В коде это часто выглядит следующим образом:


ВЫБРАТЬ
    СотрудникиОстатки.Сотрудник КАК Сотрудник,
    СотрудникиОстатки.Должность КАК Должность,
    СотрудникиОстатки.СтавкаОстатокОстаток КАК СтавкаОстатокОстаток,
    Сотрудники.Период КАК Период
ИЗ
    РегистрНакопления.Сотрудники.Остатки КАК СотрудникиОстатки,
    РегистрНакопления.Сотрудники КАК Сотрудники
ГДЕ
    Сотрудники.Период <= &Период

Выясним причину дублей: В данном запросе выбраны сразу две таблицы: виртуальная таблица Остатки и основная физическая таблица регистра Сотрудники. Между ними не указано условие связи (отсутствует ключевое слово ПО или связь в блоке ГДЕ). В терминах баз данных и SQL это порождает декартово произведение (Cross Join). Каждая строка из таблицы остатков умножается на каждую строку из физической таблицы движений, которая подходит под условие по периоду. Если у сотрудника было 10 перемещений или начислений в истории, в результате вы получите 10 одинаковых строк с текущим остатком.

Как работают виртуальные таблицы остатков

Проанализируем, чем отличаются таблицы, которые предоставляет платформа 1С. Для регистра накопления существуют:

  1. Физическая таблица: Она хранит все записи (движения), которые когда-либо делали документы. Там дубли по полям Сотрудник или Должность — это норма, так как каждая запись соответствует конкретному событию во времени.
  2. Виртуальная таблица Остатки: Она не существует в базе данных в явном виде. Система 1С формирует её "на лету", суммируя приходы и расходы из физических таблиц и итогов на указанный момент времени.

Основное правило работы в 1С: если вам нужны актуальные данные на точку времени, вы должны обращаться только к виртуальной таблице, не смешивая её с физической без крайне специфической необходимости.

Правильное использование параметров виртуальной таблицы

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


ВЫБРАТЬ
    СотрудникиОстатки.Сотрудник КАК Сотрудник,
    СотрудникиОстатки.Должность КАК Должность,
    СотрудникиОстатки.СтавкаОстатокОстаток КАК СтавкаОстатокОстаток
ИЗ
    РегистрНакопления.Сотрудники.Остатки(&Период) КАК СотрудникиОстатки

Разберем подробнее, почему этот способ является единственно верным:

Использование Конструктора запросов для настройки параметров

Посмотрим на процесс настройки через визуальный интерфейс, так как это помогает избежать синтаксических ошибок. Рассмотрим шаги настройки:

  1. Откройте Конструктор запроса.
  2. Выберите таблицу РегистрНакопления.ИмяРегистра.Остатки в левой колонке.
  3. Обратите внимание на кнопку "Параметры виртуальной таблицы" (находится над списком выбранных таблиц).
  4. В появившемся окне в поле "Период" впишите параметр &Период.
  5. В поле "Условие" можно добавить фильтры по конкретным сотрудникам или подразделениям, например: Сотрудник = &ВыбСотрудник.

Важный момент: Если вы хотите ограничить выборку конкретным сотрудником, делайте это именно в параметрах виртуальной таблицы, а не в общем списке условий запроса. Это значительно ускоряет работу программы в крупных базах.

Почему дубли могут остаться даже в правильном запросе?

Если вы применили конструкцию Остатки(&Период), но строки всё равно кажутся одинаковыми, проанализируем структуру самого регистра в Конфигураторе. Существует две скрытые причины "мнимых" дублей:

1. Невыбранные измерения

Допустим, в регистре есть три измерения: Сотрудник, Должность и Организация. В запросе вы выбираете только Сотрудник и Сумма. Если сотрудник работает в двух разных организациях, система выдаст две строки для этого сотрудника. Они будут выглядеть идентично, так как поле Организация не выведено в результат. Чтобы проверить это, попробуйте временно выбрать все измерения регистра в запросе.

2. Различия в типах данных или пустые значения

Иногда дубль возникает из-за того, что в одной записи измерение заполнено, а в другой — нет (равно NULL или пустой ссылке). В визуальном отчете обе строки могут выглядеть похожими. Всегда проверяйте чистоту данных в регистре с помощью консоли запросов, выводя детальные записи через физическую таблицу с регистратором.

Работа с периодом и границей времени

Часто путаница возникает из-за того, какая именно дата передается в параметр &Период. В 1С момент времени включает или не включает движения, совершенные в ту же секунду. Рассмотрим, как получить остатки максимально точно:

Если вам нужны остатки на конец дня, использование просто даты (например, 31.12.2023 23:59:59) может не включить документы, проведенные этой же секундой. Для решения этой задачи рекомендуется использовать объект Граница:


ГраницаПериода = Новый Граница(КонецДня(НужнаяДата), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаПериода);

Это гарантирует, что все движения, сделанные в последнюю секунду дня, будут учтены при расчете остатков в виртуальной таблице.

Итоги и рекомендации

Подводя итог, разберем краткий чек-лист для проверки запроса на "дубли":

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

← На главную