Почему в динамическом списке возникает ошибка «обнаружено дублирование ключевых значений» и как её исправить?

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

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

Причины возникновения ошибки дублирования ключевых значений

Для понимания проблемы проанализируем внутренние механизмы работы динамического списка:

  1. Назначение свойства «Основная таблица»: Когда у динамического списка задана ОсновнаяТаблица (например, Справочник.Номенклатура), платформа использует ключевое поле этой таблицы (Ссылка) для навигации, постраничного считывания данных, позиционирования курсора и кэширования. Платформа жестко требует, чтобы в выборке каждая ссылка встречалась строго один раз (связь «1 к 1»).
  2. Неполный набор измерений при соединениях: Очень часто ошибка кроется в соединении с виртуальной таблицей СрезПоследних регистра сведений (например, РегистрСведений.ЦеныНоменклатуры.СрезПоследних). Если у регистра присутствуют другие измерения, помимо номенклатуры (например, Характеристика или Упаковка), срез вернет по одной записи на каждую комбинацию измерений. В результате простого левого соединения одна ссылка на номенклатуру задвоится.
  3. Ограничения «ВЫБРАТЬ РАЗЛИЧНЫЕ»: В консоли запросов конструкция ВЫБРАТЬ РАЗЛИЧНЫЕ схлопывает полностью идентичные строки. Однако динамический список считывает данные порциями, динамически добавляя служебные поля и пользовательские настройки. Внутренний оптимизатор платформы проверяет уникальность ключевых колонок, и если связь между таблицами потенциально формирует отношение «1 ко многим» (1:N), возникает исключение.

Способ 1. Гарантированное приведение всех соединений к отношению 1:1

Разберем по шагам, как локализовать дубли и исправить запрос. Сначала выясним, какая именно таблица дает дублирование строк. Для этого выполним в консоли запросов специальный проверочный запрос без ключевого слова РАЗЛИЧНЫЕ:


ВЫБРАТЬ
    СправочникНоменклатуры.Ссылка КАК Товар,
    КОЛИЧЕСТВО(*) КАК КоличествоСтрок
ИЗ
    Справочник.Номенклатура КАК СправочникНоменклатуры
    // Подставьте сюда все ЛЕВЫЕ СОЕДИНЕНИЯ из вашего динамического списка
СГРУППИРОВАТЬ ПО
    СправочникНоменклатуры.Ссылка
ИМЕЮЩИЕ
    КОЛИЧЕСТВО(*) > 1

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

Посмотрим на пример исправления соединения с ценами. Если в регистре цен есть дополнительные измерения, обернем соединение во вложенный запрос с явной группировкой или добавим фильтры по всем измерениям:


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

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

Способ 2. Отключение свойства «Основная таблица» с программным открытием формы

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

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


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекущиеДанные <> Неопределено И ЗначениеЗаполнено(ТекущиеДанные.Товар) Тогда
        ПараметрыОткрытия = Новый Структура("Ключ", ТекущиеДанные.Товар);
        ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыОткрытия);
    КонецЕсли;
    
КонецПроцедуры

Способ 3. Использование временных таблиц в пакетном запросе

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

  1. В первой временной таблице рассчитываем и сворачиваем остатки по номенклатуре.
  2. Во второй временной таблице собираем минимальные или максимальные цены.
  3. В финальном запросе соединяем справочник Номенклатура с подготовленными временными таблицами, где гарантированно присутствует одна строка на каждый товар.

Такой подход делает структуру запроса понятной, исключает скрытые дубликаты строк и предотвращает появление ошибки дублирования ключевых значений при обновлении платформы.

← На главную