Почему в СКД появляются лишние записи при объединении с внешним источником данных PostgreSQL и как это исправить?

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

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с необходимостью объединения данных из основной базы 1С с внешними источниками (ВИД), такими как базы данных PostgreSQL, MS SQL или Oracle. Одной из наиболее запутанных проблем в такой конфигурации является мультипликация записей — ситуация, когда вместо ожидаемой одной строки в отчете появляется три, четыре или более дублей, хотя исходные запросы по отдельности возвращают корректный результат.

В этой статье мы подробно проанализируем, почему возникает эффект "размножения" строк, разберем механизм работы СКД с внешними источниками и найдем решение, связанное со спецификой трансляции функций языка запросов 1С в синтаксис PostgreSQL.

Суть проблемы: когда 1 + 1 + 1 превращается в 4

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

Многие программисты первым делом проверяют наличие дублей в самих источниках или настройки ролей полей в СКД. Но если роли не заданы, а данные чисты, причину нужно искать глубже — в механизме сопоставления типов и трансляции функций через ODBC-драйвер.

Разберем механизм соединения наборов данных в СКД

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

Проанализируем факторы, которые могут привести к некорректному сопоставлению:

  1. Несоответствие типов: Если во внешнем источнике поле имеет тип char(8), а в 1С это Строка(8), СУБД (особенно PostgreSQL) может дополнять строку пробелами до указанной длины. Для СКД строки "123" и "123 " могут считаться разными или вызывать неопределенность при сопоставлении.
  2. Обработка Null-значений: Это наиболее вероятная причина дублей. Если функция сопоставления в памяти 1С получает Null там, где ожидалось конкретное значение, алгоритм соединения может сработать по принципу Full Join или создать декартово произведение для неопределенных строк.

Конфликт функции ЕСТЬNULL в PostgreSQL

Выясним причину, связанную со спецификой PostgreSQL. В языке запросов 1С функция ЕСТЬNULL(Поле, 0) при работе с ВИД транслируется в SQL-функцию COALESCE(Поле, 0). Однако драйверы PostgreSQL иногда ведут себя специфично, если типы данных в таблице не идеально ложатся в типизацию 1С.

Рассмотрим проблемный пример кода, который часто используется в запросах к ВИД:


Выбрать
    ЕстьNull(ВнешняяТаблица.ПолеСвязи, 0) КАК ПолеСвязи,
    ВнешняяТаблица.Данные
Из
    ВнешнийИсточник.Таблица КАК ВнешняяТаблица
Где
    Не ВнешняяТаблица.ПолеСвязи ЕстьNull

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

Пошаговое решение проблемы

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

  1. Удаляем ЕСТЬNULL из выборки: Вместо того чтобы пытаться подменить Null на стороне внешней СУБД, позволим 1С получить "чистые" данные.
  2. Оставляем фильтрацию: Оставляем проверку на Null в блоке ГДЕ, чтобы не тянуть лишние пустые строки.

Исправленный код запроса для внешнего источника будет выглядеть так:


Выбрать
    ВнешняяТаблица.ПолеСвязи КАК ПолеСвязи,
    ВнешняяТаблица.Данные
Из
    ВнешнийИсточник.Таблица КАК ВнешняяТаблица
Где
    Не ВнешняяТаблица.ПолеСвязи ЕстьNull

После такого изменения драйвер передает данные напрямую, и 1С корректно типизирует их на своей стороне. Соединение в СКД начинает отрабатывать так, как ожидалось — по одной строке на каждый ключ.

Дополнительные рекомендации при работе с ВИД

Если упрощение запроса не помогло, проанализируем еще несколько важных моментов:

  1. Роли полей в СКД: Для наборов данных из внешних источников крайне желательно вручную проставить Роли. Укажите ключевые поля (флаг "Ключевое") и поля, обязательные для заполнения. Это поможет оптимизатору СКД правильно построить дерево соединения.
  2. Настройки ODBC: Проверьте параметры подключения в DSN (Data Source Name). Для PostgreSQL обратите внимание на параметры Unknown Sizes as LongVarchar и Bools as Char. Неверная интерпретация длинных строк может привести к "обрезанию" ключей связи, что также вызывает дубли.
  3. Типизация в самом ВИД: Если вы используете строки в качестве ключей связи, старайтесь, чтобы во внешней базе они имели тип varchar, а не char, чтобы избежать проблем с хвостовыми пробелами.

Таким образом, основной причиной "лишних" записей в СКД при работе с PostgreSQL часто является некорректная интерпретация функций 1С на стороне внешней СУБД. Отказ от использования ЕСТЬNULL в списке выбора запроса к ВИД — это быстрый и эффективный способ решить проблему и вернуть отчету корректный вид.

← На главную