При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с необходимостью объединения данных из основной базы 1С с внешними источниками (ВИД), такими как базы данных PostgreSQL, MS SQL или Oracle. Одной из наиболее запутанных проблем в такой конфигурации является мультипликация записей — ситуация, когда вместо ожидаемой одной строки в отчете появляется три, четыре или более дублей, хотя исходные запросы по отдельности возвращают корректный результат.
В этой статье мы подробно проанализируем, почему возникает эффект "размножения" строк, разберем механизм работы СКД с внешними источниками и найдем решение, связанное со спецификой трансляции функций языка запросов 1С в синтаксис PostgreSQL.
Рассмотрим типовую ситуацию: в СКД настроено соединение трех наборов данных. Первый набор — это запрос к основной базе 1С, а два других — запросы к внешнему источнику данных (ВИД). Соединение настроено по двум строковым полям. При проверке каждого запроса в консоли запросов мы видим по одной уникальной записи. Однако при выполнении итогового отчета в СКД данные начинают дублироваться.
Многие программисты первым делом проверяют наличие дублей в самих источниках или настройки ролей полей в СКД. Но если роли не заданы, а данные чисты, причину нужно искать глубже — в механизме сопоставления типов и трансляции функций через ODBC-драйвер.
Важно понимать, что когда мы соединяем данные из разных источников (особенно если один из них внешний), платформа 1С выполняет эти запросы независимо. Соединение (Join) происходит не на стороне SQL-сервера, а "в памяти" на сервере приложений 1С. Платформа получает результаты из базы 1С и результаты из внешнего источника, а затем пытается сопоставить их по полям связи.
Проанализируем факторы, которые могут привести к некорректному сопоставлению:
char(8), а в 1С это Строка(8), СУБД (особенно PostgreSQL) может дополнять строку пробелами до указанной длины. Для СКД строки "123" и "123 " могут считаться разными или вызывать неопределенность при сопоставлении.Null там, где ожидалось конкретное значение, алгоритм соединения может сработать по принципу Full Join или создать декартово произведение для неопределенных строк.Выясним причину, связанную со спецификой PostgreSQL. В языке запросов 1С функция ЕСТЬNULL(Поле, 0) при работе с ВИД транслируется в SQL-функцию COALESCE(Поле, 0). Однако драйверы PostgreSQL иногда ведут себя специфично, если типы данных в таблице не идеально ложатся в типизацию 1С.
Рассмотрим проблемный пример кода, который часто используется в запросах к ВИД:
Выбрать
ЕстьNull(ВнешняяТаблица.ПолеСвязи, 0) КАК ПолеСвязи,
ВнешняяТаблица.Данные
Из
ВнешнийИсточник.Таблица КАК ВнешняяТаблица
Где
Не ВнешняяТаблица.ПолеСвязи ЕстьNull
Проанализируем ситуацию: в списке выбора мы используем ЕстьNull, а в условии фильтрации отсекаем пустые значения. Казалось бы, логика безупречна. Но на практике, из-за особенностей трансляции запроса и работы оптимизатора 1С, комбинация этих условий может приводить к тому, что драйвер возвращает некорректно типизированное значение, которое СКД воспринимает как Null. Это ломает логику соединения в памяти сервера 1С, и мы получаем лишние записи.
Чтобы устранить мультипликацию записей, необходимо упростить запрос к внешнему источнику, максимально исключив из него функции преобразования типов в списке выбора. Посмотрим на исправленный вариант:
Null на стороне внешней СУБД, позволим 1С получить "чистые" данные.Null в блоке ГДЕ, чтобы не тянуть лишние пустые строки.Исправленный код запроса для внешнего источника будет выглядеть так:
Выбрать
ВнешняяТаблица.ПолеСвязи КАК ПолеСвязи,
ВнешняяТаблица.Данные
Из
ВнешнийИсточник.Таблица КАК ВнешняяТаблица
Где
Не ВнешняяТаблица.ПолеСвязи ЕстьNull
После такого изменения драйвер передает данные напрямую, и 1С корректно типизирует их на своей стороне. Соединение в СКД начинает отрабатывать так, как ожидалось — по одной строке на каждый ключ.
Если упрощение запроса не помогло, проанализируем еще несколько важных моментов:
Unknown Sizes as LongVarchar и Bools as Char. Неверная интерпретация длинных строк может привести к "обрезанию" ключей связи, что также вызывает дубли.varchar, а не char, чтобы избежать проблем с хвостовыми пробелами.Таким образом, основной причиной "лишних" записей в СКД при работе с PostgreSQL часто является некорректная интерпретация функций 1С на стороне внешней СУБД. Отказ от использования ЕСТЬNULL в списке выбора запроса к ВИД — это быстрый и эффективный способ решить проблему и вернуть отчету корректный вид.