Каждый разработчик 1С рано или поздно сталкивается с ситуацией, когда созданный им отчет в Системе компоновки данных (СКД) идеально работает под полными правами администратора, но выдает ошибку при запуске обычным пользователем. Одной из наиболее коварных и труднодиагностируемых проблем является ошибка: «Ошибка обработки представления. Несоответствие типов (Параметр номер 1)» или «Несоответствие типов параметров».
В этой статье мы подробно разберем, почему возникает эта ошибка при связи наборов данных по полю Регистратор.Дата, проанализируем внутренние механизмы работы платформы 1С и СУБД под ограниченными правами, а также рассмотрим пять надежных способов решения данной проблемы.
Рассмотрим классический пример, с которым столкнулся автор темы на форуме. В отчете СКД настроены два набора данных:
Набор данных №1 (Источник): Запрос к виртуальной таблице оборотов регистра накопления ВыручкаИСебестоимостьПродаж.Обороты. В этом запросе программист выбирает поле ВыручкаИСебестоимостьПродажОбороты.Регистратор.Дата и дает ему псевдоним Период.
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ВыручкаИСебестоимостьПродажОбороты.Регистратор.Дата КАК Период,
ВыручкаИСебестоимостьПродажОбороты.Регистратор КАК Регистратор,
ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаНоменклатуры.Номенклатура КАК Номенклатура,
ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаНоменклатуры.Характеристика КАК Характеристика
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода, Авто, ) КАК ВыручкаИСебестоимостьПродажОбороты
Набор данных №2 (Приемник): Запрос к виртуальной таблице среза последних регистра сведений ЦеныНоменклатуры.СрезПоследних. Параметр &Дата этой таблицы заполняется из связи наборов данных.
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ЦеныНоменклатурыСрезПоследних.Период,
ЦеныНоменклатурыСрезПоследних.Номенклатура,
ЦеныНоменклатурыСрезПоследних.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&Дата,
ВидЦены = &ВидЦены
И Номенклатура = &Номенклатура
И Характеристика = &Характеристика) КАК ЦеныНоменклатурыСрезПоследних
Связь наборов данных: Источник связи — Период, Приемник связи — параметр &Дата во втором наборе данных.
Выясним причину, почему эта схема дает сбой у обычного пользователя. При обращении через точку к реквизиту ссылки (в нашем случае Регистратор.Дата), платформа 1С на уровне СУБД генерирует неявное левое соединение (LEFT JOIN) со всеми таблицами документов, которые могут являться регистраторами для данного регистра накопления.
Если у пользователя ограничены права (например, настроен RLS — Row-Level Security на уровне записей или отсутствуют права на чтение хотя бы одного из видов документов-регистраторов), происходят следующие процессы:
NULL вместо даты регистратора.&Дата для виртуальной таблицы СрезПоследних. Виртуальная таблица ожидает на входе строгий тип Дата. Получив вместо даты значение NULL (или составной тип, содержащий NULL), СУБД не может обработать представление и выдает ошибку несоответствия типов.Рассмотрим детально методы решения этой проблемы, начиная от самых быстрых и заканчивая наиболее оптимальными с точки зрения производительности.
Самый простой способ исправить ошибку без изменения логики запросов — жестко указать тип передаваемого поля на уровне схемы компоновки данных. Это заставит СКД автоматически приводить все значения к нужному типу на этапе компоновки результата.
Выполним следующие шаги:
Период (в которое выбирается дата регистратора).Благодаря этому действию СКД при формировании временных таблиц связи преобразует любые значения NULL в пустую дату, что предотвратит падение запроса.
Если вы хотите гарантировать совместимость типов непосредственно на уровне SQL-запроса, мы можем использовать встроенную функцию ВЫРАЗИТЬ. Это исключит передачу неопределенных типов данных в механизм связи СКД.
Изменим выборку поля даты регистратора в первом наборе данных следующим образом:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ВЫРАЗИТЬ(ВыручкаИСебестоимостьПродажОбороты.Регистратор.Дата КАК ДАТА) КАК Период,
ВыручкаИСебестоимостьПродажОбороты.Регистратор КАК Регистратор,
...
Функция ВЫРАЗИТЬ принудительно преобразует результат обращения через точку в тип Дата, отсекая потенциальные конфликты типов СУБД для пользователей с ограниченными правами.
Обращение к реквизитам регистратора через точку (Регистратор.Дата) в таблицах оборотов — это крайне неоптимальное решение с точки зрения производительности 1С. Оно заставляет СУБД выполнять десятки левых соединений со всеми таблицами документов-регистраторов, что сильно замедляет отчет даже под полными правами.
Виртуальная таблица оборотов уже содержит готовые и оптимизированные системные поля периодов. Проанализируем структуру первого набора данных: в нем уже выбираются поля периодичности (ПериодСекунда, ПериодДень и т.д.). Мы можем использовать их.
Для оптимизации отчета выполним следующие действия:
ВыручкаИСебестоимостьПродажОбороты.Регистратор.Дата на стандартное поле периодичности, например, ВыручкаИСебестоимостьПродажОбороты.ПериодСекунда (или ПериодДень, в зависимости от требуемой точности).Период.
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ВыручкаИСебестоимостьПродажОбороты.ПериодСекунда КАК Период,
ВыручкаИСебестоимостьПродажОбороты.Регистратор КАК Регистратор,
...
Поля группы Период... виртуальной таблицы гарантированно имеют тип Дата, никогда не возвращают значение NULL (даже при жестких ограничениях RLS на документы) и работают в разы быстрее, так как платформа считывает их напрямую из таблицы движений регистра без лишних соединений.
Если специфика бизнес-логики отчета требует использовать исключительно дату регистратора (хотя в большинстве случаев варианты 1 и 3 предпочтительнее), мы можем обезопасить передаваемый параметр от попадания пустых значений с помощью функции ЕСТЬNULL.
Настроим запрос первого набора данных следующим образом:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ЕСТЬNULL(ВыручкаИСебестоимостьПродажОбороты.Регистратор.Дата, ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)) КАК Период,
ВыручкаИСебестоимостьПродажОбороты.Регистратор КАК Регистратор,
...
Если из-за отсутствия прав или настроек RLS система вернет пустую запись, функция ЕСТЬNULL заменит ее на пустую дату начала временной шкалы 1С (01.01.0001 00:00:00). СУБД успешно передаст эту дату во второй набор данных, и отчет сформируется без системных ошибок.
Еще один профессиональный прием работы в СКД — использование возможностей расширения языка запросов для компоновки данных. Мы можем сделать параметр даты во втором наборе данных необязательным, заключив его в фигурные скобки.
Модифицируем текст запроса второго набора данных:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
ЦеныНоменклатурыСрезПоследних.Период,
ЦеныНоменклатурыСрезПоследних.Номенклатура,
ЦеныНоменклатурыСрезПоследних.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
{&Дата},
ВидЦены = &ВидЦены
И Номенклатура = &Номенклатура
И Характеристика = &Характеристика) КАК ЦеныНоменклатурыСрезПоследних
Использование конструкции {&Дата} указывает компоновщику данных, что данный параметр является необязательным. Если при связи наборов данных СКД столкнется с несовместимым типом или пустым значением, система корректно обработает запрос и построит представление без аварийного завершения работы отчета.
Мы подробно разобрали причины возникновения ошибки несоответствия типов параметров в СКД. Как мы выяснили, корень проблемы лежит в неявных соединениях СУБД при обращении к реквизитам ссылочного типа под ограниченными правами пользователей.
Для предотвращения подобных ошибок в вашей практике рекомендуем придерживаться золотого правила разработки отчетов в 1С: никогда не использовать обращение к реквизитам документов через точку (таким как Регистратор.Дата) в виртуальных таблицах оборотов. Всегда отдавайте предпочтение стандартным полям периодов (ПериодСекунда, ПериодДень), так как это гарантирует стабильную работу прав доступа и существенно повышает скорость построения отчетов.