Как исправить ошибку «Дублирование ключевых значений в колонках "Ссылка"» в динамическом списке 1С

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

При разработке в среде 1С программисты часто сталкиваются с необходимостью расширить стандартные журналы документов или списки, добавив в них дополнительные колонки из регистров. Одной из самых коварных ошибок при выполнении этой задачи является «Дублирование ключевых значений в колонках "Ссылка"». Особенно часто это проявляется при работе с электронными счетами-фактурами (ЭСФ), где одному документу-основанию может соответствовать несколько записей в системе. В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем типичный ошибочный запрос и реализуем правильное решение.

Выясним причину возникновения ошибки

Для начала разберем внутреннюю механику работы 1С. Когда мы настраиваем динамический список (например, список документов РеализацияТоваровУслуг) и указываем в нем Основную таблицу, платформа ожидает, что каждая строка в результате запроса будет уникальной по полю Ссылка. Это необходимо для корректной работы навигации, выделения строк, работы контекстного меню и кэширования данных в памяти клиента.

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

Проанализируем ошибочный запрос

Рассмотрим пример кода, который чаще всего приводит к проблеме при попытке вывести дату ЭСФ в список реализаций. Автор темы использовал следующий подход:


ВЫБРАТЬ
    АктуальныеЭСФ.СчетФактура.Дата КАК СчетФактураДата,
    АктуальныеЭСФ.ЭСФ.Дата КАК ЭСФДата,
    РеализацияТоваровУслуг.Ссылка КАК Ссылка
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.АктуальныеЭСФ КАК АктуальныеЭСФ
        ПО РеализацияТоваровУслуг.Ссылка = АктуальныеЭСФ.СчетФактура.ДокументОснование

Почему это не работает? В данном случае соединение происходит по условию соответствия ссылки реализации полю ДокументОснование в регистре. В учетных системах (особенно в Казахстане) по одной реализации может быть выписано несколько ЭСФ в разных статусах. Следовательно, в регистре АктуальныеЭСФ может быть несколько записей для одной реализации. В итоге динамический список получает дублирующиеся ссылки.

Решение №1: Использование агрегатных функций и группировки

Самый простой и эффективный способ избавиться от дублей в динамическом списке — это «схлопнуть» результат запроса с помощью группировки. Мы должны гарантировать, что для каждой уникальной ссылки документа будет выбрана только одна запись из регистра. Обычно бухгалтеру важно видеть дату самого последнего (актуального) счета-фактуры. Для этого мы используем функцию МАКСИМУМ.

Давайте перепишем запрос правильно:


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

Важные замечания к этому решению:

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

Решение №2: Фильтрация по статусу актуальности

Зачастую в регистрах, хранящих сведения о документах, есть специальные флаги или состояния (например, поле Состояние или Актуально). Если нам не подходит вариант с МАКСИМУМ, мы можем наложить условие прямо в соединении таблиц, чтобы выбрать только «ту самую» единственную запись.

Рассмотрим этот вариант подробнее:


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

Здесь мы добавили условие АктуальныеЭСФ.Состояние = ... непосредственно в условие ПО. Это позволяет отсечь черновые или аннулированные записи еще на этапе соединения таблиц. Однако этот метод сработает только в том случае, если вы на 100% уверены, что в статусе «Принят сервером» у документа может быть только одна запись.

Решение №3: Вложенный запрос (для сложных случаев)

Если структура данных такова, что простым фильтром или группировкой не обойтись (например, нужно выводить данные из нескольких связанных полей одного и того же регистра), рекомендуется использовать вложенный запрос. Сначала мы выбираем уникальные пары Ссылка-МаксимальныйID, а затем соединяем их с данными регистра.

Разберем этот пример по шагам:


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

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

Как найти «проблемные» документы в базе

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


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

Результат этого запроса покажет вам ссылки на документы, у которых в регистре АктуальныеЭСФ числится более одной записи. Проанализировав эти документы вручную, вы поймете, какой дополнительный фильтр (например, по признаку ЭтоИсправленный или Статус) нужно добавить в ваш запрос для динамического списка, чтобы гарантировать уникальность ключевого поля Ссылка.

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

← На главную