Почему задваивается поле КоличествоКонечныйОстаток при соединении с регистром цен и как это исправить?

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

Одной из самых распространенных проблем, с которой сталкиваются начинающие разработчики 1С при построении отчетов, является «размножение» строк в результате запроса. Особенно часто это происходит при попытке соединить данные о складских остатках с ценами из регистра сведений. Вместо ожидаемой одной строки по одной позиции номенклатуры мы получаем две, три или более, что приводит к некорректным итогам и «чудесам» в СКД. В этой статье мы подробно разберем, почему так происходит, и как правильно составить запрос, чтобы данные оставались верными.

Причина возникновения дублей: Механика левого соединения

Давайте проанализируем ситуацию. Когда мы выполняем ЛЕВОЕ СОЕДИНЕНИЕ таблицы остатков с таблицей цен, система ищет соответствие для каждой строки из левой таблицы (остатки) в правой таблице (цены). Если в правой таблице по заданному условию связи находится более одной записи, то строка из левой таблицы будет продублирована столько раз, сколько соответствий найдено.

Рассмотрим пример. Допустим, на складе числится 10 единиц товара «Ботинки». В регистре сведений «Цены» для этого товара зафиксировано две цены: одна для характеристики «Размер 42», другая для характеристики «Размер 43». Если в запросе мы соединяем таблицы только по полю Номенклатура, игнорируя характеристики, система выдаст две строки по 10 единиц, и в итоге мы получим 20 единиц товара, что не соответствует действительности.

Разбор типичных ошибок в запросе

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


ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.КоличествоОстаток,
    ЦеныСрезПоследних.Цена,
    ЦеныСрезПоследних.Период
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки(&Период, ) КАК Остатки
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены.СрезПоследних КАК ЦеныСрезПоследних
    ПО Остатки.Номенклатура = ЦеныСрезПоследних.Номенклатура
ГДЕ
    ЦеныСрезПоследних.Период МЕЖДУ &Начало И &Конец

В этом фрагменте допущено сразу несколько критических ошибок, которые мы сейчас разберем по шагам.

Шаг 1: Учет всех измерений в условии связи

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

ПО Остатки.Номенклатура = ЦеныСрезПоследних.Номенклатура И Остатки.Характеристика = ЦеныСрезПоследних.Характеристика

Если пропустить Характеристика, то на каждую характеристику остатка «наложится» каждая характеристика из регистра цен, что и вызовет геометрическую прогрессию строк.

Шаг 2: Правильное использование параметров виртуальных таблиц

Обратим внимание на блок ГДЕ. Использование условия ЦеныСрезПоследних.Период МЕЖДУ &Начало И &Конец — это классическая методическая ошибка. Виртуальная таблица СрезПоследних предназначена для получения одной наиболее актуальной записи на конкретный момент времени.

Когда вы ставите фильтр в ГДЕ, вы сначала получаете срез последних цен на текущую дату (или дату, указанную в параметрах), а затем «отрезаете» те записи, дата установки которых не попала в интервал. Это не даст вам цен за период, но может привести к потере данных или их некорректному отображению. Для правильной работы фильтр по типу цен или другим измерениям нужно передавать непосредственно в параметры виртуальной таблицы.

Посмотрим на правильное оформление параметров:


РегистрСведений.Цены.СрезПоследних(&КонецПериода, ТипЦен = &НужныйТипЦен) КАК ЦеныСрезПоследних

Шаг 3: Исключение лишних полей из выборки (поле Период)

Часто программисты добавляют поле Период из регистра цен в раздел ВЫБРАТЬ, чтобы видеть, когда была установлена цена. Однако именно это поле может стать причиной дублей в результате запроса, если для одной номенклатуры в базе данных по какой-то причине оказалось несколько актуальных записей на одну и ту же дату (например, из-за разных секунд или других неявных измерений).

Проанализируем ситуацию: если нам нужен остаток на конец дня, нам важна сама цена, а не дата её установки. Удалив поле Период из списка выбираемых полей, мы позволяем платформе (и СКД) более эффективно группировать строки.

Шаг 4: Поиск скрытых измерений

Если вышеописанные методы не помогли, выполним диагностику. Добавим в запрос выборку всех полей из регистра цен, используя символ *:

ВЫБРАТЬ Остатки.Номенклатура, ЦеныСрезПоследних.* ...

Запустив такой запрос в консоли, мы сможем увидеть, какие именно колонки различаются в дублирующихся строках. Возможно, в регистре цен есть скрытое измерение, такое как Организация, ЕдиницаИзмерения или Спецификация, о котором вы забыли. Найдя это поле, добавьте его в условие связи или ограничьте его значение в параметрах виртуальной таблицы.

Итоговый правильный вариант запроса

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


ВЫБРАТЬ
    Остатки.Склад,
    Остатки.Номенклатура,
    Остатки.Характеристика,
    Остатки.КоличествоОстаток КАК КоличествоКонечныйОстаток,
    ЕСТЬNULL(ЦеныСрезПоследних.Цена, 0) КАК ЦенаЗакупки
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки(&КонецПериода, ) КАК Остатки
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены.СрезПоследних(&КонецПериода, ТипЦен = &ТипЦенЗакупки) КАК ЦеныСрезПоследних
    ПО Остатки.Номенклатура = ЦеныСрезПоследних.Номенклатура
    И Остатки.Характеристика = ЦеныСрезПоследних.Характеристика

Важные моменты:

  1. Используйте ЕСТЬNULL для цен, чтобы избежать пустых значений, если цена для товара не задана.
  2. Никогда не используйте .Ссылка в условиях связи запроса (например, Номенклатура.Ссылка) — это создает лишнее обращение к таблице справочника и замедляет работу. Поля Номенклатура в регистрах уже являются ссылками.
  3. В СКД для поля КоличествоКонечныйОстаток обязательно проверьте настройки роли поля. Должна быть указана роль Остатки, задано имя и тип (Конечный остаток), чтобы СКД правильно агрегировала данные по иерархии и периодам.

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

← На главную