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