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