Почему возникает ошибка «Несовместимые типы ОБЪЕДИНИТЬ» в Универсальном отчете и как ее исправить?

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

При работе с конфигурациями на обычных формах, такими как УПП 1.3 или УТ 10.3, разработчики часто прибегают к использованию Универсального отчета. Этот инструмент базируется на механизме Построителя отчета и позволяет быстро создавать отчеты на основе произвольных запросов. Однако при попытке объединить несколько источников данных через оператор ОБЪЕДИНИТЬ ВСЕ (UNION ALL), можно столкнуться с ошибкой: «Несовместимые типы "ОБЪЕДИНИТЬ"». Примечательно, что этот же запрос в обычной консоли запросов может выполняться без ошибок. Рассмотрим подробнее, почему это происходит и как правильно сконструировать запрос для Универсального отчета.

Разбор ситуации: запрос работает в консоли, но падает в отчете

Проанализируем типичный сценарий. Разработчик пишет сложный запрос, где во вложенном запросе объединяются данные из разных таблиц: документов (например, ПланПродаж), остатков и оборотов различных регистров (ТоварыНаСкладах, Продажи). В списке выбора каждой части объединения присутствуют колонки для дат. В первой части объединения вместо реального поля таблицы часто подставляется параметр периода, например &ДатаНач.

В консоли запросов мы обычно передаем в параметры простую дату. Но Универсальный отчет (УО) работает иначе. Для корректной работы виртуальных таблиц (получения остатков на начало и конец секунды) УО передает в параметры &ДатаНачала и &ДатаКонца не просто тип Дата, а объект Граница (Boundary).

Объект Граница — это специальный тип данных 1С, который включает в себя не только момент времени, но и вид границы (включая или исключая этот момент). Именно здесь кроется корень проблемы.

Причина 1: Конфликт типов Дата и Граница в операторе ОБЪЕДИНИТЬ

Согласно правилам работы SQL и движка запросов 1С, при использовании оператора ОБЪЕДИНИТЬ типы данных в соответствующих колонках всех объединяемых частей должны быть идентичными. Более того, тип итоговой колонки всего объединения определяется по первой части запроса.

Рассмотрим фрагмент кода, вызывающий ошибку:


ИЗ
    (ВЫБРАТЬ
        ПланПродаж.Ссылка КАК Регистратор,
        &ДатаНач КАК ДатаПродажи  // Здесь Построитель подставит тип "Граница"
    ИЗ
        Документ.ПланПродаж КАК ПланПродаж
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        Продажи.ДокументПродажи,
        Продажи.ДокументПродажи.Дата // Здесь в БД хранится тип "Дата"
    ИЗ
        РегистрНакопления.Продажи.Обороты(...) КАК Продажи)

Выясним причину сбоя: в первой части объединения в колонку ДатаПродажи попадает объект Граница. Во второй части в ту же колонку система пытается поместить значение ДокументПродажи.Дата, которое имеет тип Дата. Поскольку Граница и Дата — это разные типы данных, 1С выдает ошибку о несовместимости типов. В консоли запросов ошибка может не проявляться, если вы вручную указали параметр как дату, но Универсальный отчет управляет параметрами автоматически, подставляя туда служебные объекты.

Причина 2: Специфика Построителя отчета

Важно понимать, что Универсальный отчет использует Построитель отчета. Этот механизм перед выполнением запроса производит его текстовую модификацию. Он анализирует секции в фигурных скобках {} и автоматически подставляет параметры. Если поле указано в списке выбора и при этом является параметром периода, Построитель может попытаться типизировать его так, как ему удобно для работы с виртуальными таблицами, что часто приводит к конфликтам в конструкциях UNION.

Решение 1: Явное приведение типов через ВЫРАЗИТЬ

Чтобы заставить систему воспринимать параметр периода как обычную дату, необходимо использовать функцию ВЫРАЗИТЬ. Это самый надежный способ гарантировать совместимость типов во всех частях объединения. Посмотрим на пример исправления:


ВЫБРАТЬ
    ВложенныйЗапрос.ДатаПродажи
ИЗ
    (ВЫБРАТЬ
        // Принудительно приводим параметр к типу Дата
        ВЫРАЗИТЬ(&ДатаНач КАК ДАТА) КАК ДатаПродажи
    ИЗ
        Документ.ПланПродаж КАК ПланПродаж
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        ПродажиОбороты.ДокументПродажи.Дата
    ИЗ
        РегистрНакопления.Продажи.Обороты(,,,) КАК ПродажиОбороты) КАК ВложенныйЗапрос

Функция ВЫРАЗИТЬ(... КАК ДАТА) «отсекает» от объекта Граница его специфические свойства, оставляя только значение времени, что делает его совместимым с полями дат из таблиц базы данных.

Решение 2: Использование функции НАЧАЛОПЕРИОДА

Другой способ неявного преобразования — использование функций работы с датами, таких как НАЧАЛОПЕРИОДА. Эти функции на вход могут принимать Границу, но на выходе всегда возвращают чистый тип Дата. Рассмотрим, как это применить:


ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(&ДатаНачала, ДЕНЬ) КАК ДатаНачалаКолонка
ИЗ
    ...
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
    Документ.Дата
ИЗ
    ...

Этот метод часто используется в типовых конфигурациях 1С, так как он дополнительно позволяет нормализовать время (сбросить его в 00:00:00), что удобно для группировки данных по дням.

Решение 3: Изменение структуры объединения

Проанализируем архитектуру запроса. Если нам нужно вывести дату в Универсальном отчете, зачастую правильнее брать её не из параметров периода (которые одинаковы для всех строк), а из реальных полей данных. Если же параметр &ДатаНач нужен просто как «заглушка» для тех строк, где дата не определена, можно использовать литерал пустой даты:


ВЫБРАТЬ
    ДАТАВРЕМЯ(1, 1, 1) КАК ДатаСобытия
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаНач)

В этом случае тип колонки в первой части объединения будет Дата, и все последующие части с реальными датами документов успешно объединятся.

Важные рекомендации по работе с Универсальным отчетом

При написании запросов для Универсального отчета следует придерживаться следующих правил, чтобы избежать ошибок типизации и производительности:

  1. Синхронизация полей: Следите за тем, чтобы во всех частях ОБЪЕДИНИТЬ колонки шли в одинаковом порядке и имели совместимые типы. Если в первой таблице поле Регистратор имеет тип ДокументСсылка.Продажа, а во второй — ДокументСсылка.Поступление, итоговое поле будет составным. Это нормально, но может замедлить отчет.
  2. Фигурные скобки: Правильно описывайте поля в секциях {ВЫБРАТЬ}, {ГДЕ} и {ИТОГИ}. Если поле добавлено в объединение, оно должно быть доступно для построителя, иначе отборы по нему работать не будут.
  3. Избегайте Границ в выборе: Никогда не выводите параметры &ДатаНачала и &ДатаКонца напрямую в список ВЫБРАТЬ внутри объединений без использования ВЫРАЗИТЬ.
  4. Группировка: Если вы используете вложенный запрос с объединением, всегда делайте финальную группировку (СГРУППИРОВАТЬ ПО) во внешнем запросе, чтобы объединить данные по одинаковым измерениям (например, по номенклатуре) из разных источников.

Таким образом, основная сложность ошибки «Несовместимые типы» в Универсальном отчете заключается в скрытой передаче объекта Граница вместо даты. Использование явного приведения типов или функций обработки дат позволяет полностью решить эту проблему и успешно объединять данные из регистров остатков, оборотов и документов в одном отчете.

← На главную