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