Почему возникает ошибка «Обнаружено дублирование поля Ссылка» в динамическом списке 1С и как её исправить

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

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

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

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

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

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

Выясним, как это выглядит на практике. Ниже приведен пример запроса, вызывающего ошибку:


ВЫБРАТЬ
	ДокументЗаявкаНаВозвратТоваровПоставщику.Ссылка КАК Ссылка,
	ДокументЗаявкаНаВозвратТоваровПоставщику.Номер КАК Номер,
	ДокументЗаявкаНаВозвратТоваровПоставщику.Дата КАК Дата,
	ВЫБОР
		КОГДА ТоварыНаСкладах.ВНаличии > 0
			ТОГДА 100
		ИНАЧЕ 0
	КОНЕЦ КАК ПоступлениеТовара
ИЗ
	Документ.ЗаявкаНаВозвратТоваровПоставщику КАК ДокументЗаявкаНаВозвратТоваровПоставщику
		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
		ПО ДокументЗаявкаНаВозвратТоваровПоставщику.ДокументОснование = ТоварыНаСкладах.Регистратор.Распоряжение.ЗаявкаНаВозвратТоваровОтКлиента

Поскольку документ-основание имеет несколько записей движений в регистре ТоварыНаСкладах, один документ повторится в выборке столько раз, сколько движений зарегистрировано по нему. Платформа фиксирует повторяющиеся элементы Ссылка и выдает ошибку при открытии формы.

Ошибка обращения к составным типам через несколько точек

Обратим внимание на еще один критический момент в запросе — конструкцию разворачивания полей через несколько точек:

ТоварыНаСкладах.Регистратор.Распоряжение.ЗаявкаНаВозвратТоваровОтКлиента

Поле Регистратор в физических таблицах регистров накопления всегда имеет составной тип данных. Обращение к составному типу через точку заставляет СУБД генерировать сложные соединения (LEFT JOIN или UNION ALL) со всеми таблицами документов, которые могут выступать регистраторами для данного регистра. Добавление цепочки дальнейших обращений к реквизитам делает запрос крайне неэффективным и приводит к сильным задержкам при прокрутке и поиске в динамическом списке.

Способы решения проблемы

Рассмотрим по шагам основные способы исправления ошибки в зависимости от поставленной задачи.

  1. Предварительная агрегация данных в подзапросе

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

    
    ВЫБРАТЬ
    	Заявка.Ссылка КАК Ссылка,
    	Заявка.Номер КАК Номер,
    	Заявка.Дата КАК Дата,
    	ЕСТЬНУЛЛ(ВложенныйЗапрос.ПоступлениеТовара, 0) КАК ПоступлениеТовара
    ИЗ
    	Документ.ЗаявкаНаВозвратТоваровПоставщику КАК Заявка
    		ЛЕВОЕ СОЕДИНЕНИЕ (
    			ВЫБРАТЬ
    				Движения.Регистратор КАК Регистратор,
    				МАКСИМУМ(ВЫБОР КОГДА Движения.ВНаличии > 0 ТОГДА 100 ИНАЧЕ 0 КОНЕЦ) КАК ПоступлениеТовара
    			ИЗ
    				РегистрНакопления.ТоварыНаСкладах КАК Движения
    			ГРУППИРОВАТЬ ПО
    				Движения.Регистратор
    		) КАК ВложенныйЗапрос
    		ПО Заявка.ДокументОснование = ВложенныйЗапрос.Регистратор
    
  2. Использование оператора условия с проверкой вхождения (В / EXISTS)

    Если требуется лишь установить факт наличия связанных записей или признака (например, получить 100 или 0), вместо соединения таблиц можно использовать условие проверкой вхождения ссылки в подзапрос с уникальным списком:

    
    ВЫБРАТЬ
    	Заявка.Ссылка КАК Ссылка,
    	Заявка.Номер КАК Номер,
    	Заявка.Дата КАК Дата,
    	ВЫБОР
    		КОГДА Заявка.ДокументОснование В (
    			ВЫБРАТЬ РАЗЛИЧНЫЕ
    				ТоварыНаСкладах.Регистратор
    			ИЗ
    				РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
    			ГДЕ
    				ТоварыНаСкладах.ВНаличии > 0
    		) ТОГДА 100
    		ИНАЧЕ 0
    	КОНЕЦ КАК ПоступлениеТовара
    ИЗ
    	Документ.ЗаявкаНаВозвратТоваровПоставщику КАК Заявка
    
  3. Использование регистров сведений для быстрого отображения статусов

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

← На главную