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

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

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

Причина возникновения ошибки в динамическом списке

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

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

Способ 1. Агрегация данных во вложенном запросе (рекомендуемый вариант)

Чтобы исключить появление повторяющихся ссылок, необходимо гарантировать, что присоединяемая таблица возвращает ровно одну строку для каждого документа-основания. Для этого применим группировку по ключевому полю связи и используем агрегатную функцию для даты.

Рассмотрим, как изменить вложенный запрос с получением даты последней фактической оплаты:


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

Разберем ключевые изменения в тексте запроса:

  1. Добавлена конструкция СГРУППИРОВАТЬ ПО ПлатежноеПоручение.ДокументОснование, исключающая дублирование документов-оснований.
  2. Для поля даты применена агрегатная функция МАКСИМУМ(ПлатежноеПоручение.Дата) (или МИНИМУМ, если требуется дата первой оплаты).
  3. В функции ЕСТЬNULL числовое значение 0 заменено на пустую дату ДАТАВРЕМЯ(1, 1, 1). Использование числа вместо даты приводит к несовместимости типов в колонке динамического списка и ошибкам форматирования.

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

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

Посмотрим на структуру такого пакетного запроса:


ВЫБРАТЬ
    ПлатежноеПоручение.ДокументОснование КАК ДокументОснование,
    МАКСИМУМ(ПлатежноеПоручение.Дата) КАК ДатаОплаты
ПОМЕСТИТЬ ВТ_Оплаты
ИЗ
    Документ.ПлатежноеПоручение КАК ПлатежноеПоручение
ГДЕ
    ПлатежноеПоручение.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО
    ПлатежноеПоручение.ДокументОснование

ИНДЕКСИРОВАТЬ ПО
    ДокументОснование
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ДокументСчетНаОплатуПоставщика.Ссылка КАК Ссылка,
    ДокументСчетНаОплатуПоставщика.Номер КАК Номер,
    ДокументСчетНаОплатуПоставщика.Дата КАК Дата,
    ЕСТЬNULL(ВТ_Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОплаты
ИЗ
    Документ.СчетНаОплатуПоставщика КАК ДокументСчетНаОплатуПоставщика
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Оплаты КАК ВТ_Оплаты
    ПО (ВТ_Оплаты.ДокументОснование = ДокументСчетНаОплатуПоставщика.Ссылка)

Ограничения и методические особенности учета

При доработке запросов счетов и платежей важно учитывать логику типовых конфигураций («1С:Бухгалтерия предприятия», «1С:ERP», «1С:Комплексная автоматизация»):

  1. Различие документов оплаты: Документ ПлатежноеПоручение является лишь намерением перечислить средства и не формирует движений по счетам учета. Фактическое движение денег фиксируется документом СписаниеСРасчетногоСчета.
  2. Многострочные платежи: Счет на оплату может быть указан не только в реквизите шапки ДокументОснование, но и в табличной части платежного документа (например, при оплате нескольких счетов одной платежкой).
  3. Регистры статусов: В типовых решениях статус и состояние оплаты рассчитываются через специализированные регистры сведений (например, СтатусыДокументов) или регистры взаиморасчетов, что позволяет избежать прямого обращения к документам движения.
← На главную