Как исправить ошибку «Несоответствие типов (Параметр номер 1)» в СКД при использовании виртуальной таблицы СрезПоследних?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Разбор причины возникновения ошибки несоответствия типов

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

Конфликт возникает в тот момент, когда в схеме компоновки данных определен стандартный параметр Период с типом СтандартныйПериод. Система компоновки пытается передать весь этот объект (содержащий дату начала и дату окончания) в качестве первого параметра виртуальной таблицы, которой нужна только одна конкретная дата. В результате мы получаем ошибку: «Несоответствие типов (Параметр номер "1")».

Выясним причину на конкретном примере запроса, который использовал автор темы:


ВЫБРАТЬ
    РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
    РеализацияТоваровУслугТовары.Количество КАК Количество,
    ЦеныНоменклатурыСрезПоследних.Цена КАК ЦенаЗакупки
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних 
    ПО РеализацияТоваровУслугТовары.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
ГДЕ 
    РеализацияТоваровУслугТовары.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

В данном случае в соединении указано РегистрСведений.ЦеныНоменклатуры.СрезПоследних без явных параметров. Проанализируем, как это исправить.

Шаг 1: Настройка параметров на закладке «Параметры» СКД

Рассмотрим по шагам, как правильно сконфигурировать параметры, чтобы избежать конфликтов типов:

  1. Откроем схему компоновки данных и перейдем на закладку «Параметры».
  2. Найдем параметр Период. Если он имеет тип СтандартныйПериод, нам нужно создать вспомогательные параметры, которые будут передавать конкретные даты в запрос.
  3. Для параметра ДатаНачала в колонке «Выражение» укажем: &Период.ДатаНачала.
  4. Для параметра ДатаОкончания укажем: &Период.ДатаОкончания.
  5. Важный момент: если ваша виртуальная таблица должна возвращать цены на конец выбранного периода, нам нужно создать параметр для самой таблицы. Обычно он называется Период (но для виртуальной таблицы) или ДатаСреза.
  6. В выражении этого параметра укажем КонецДня(&ДатаОкончания), чтобы захватить последние изменения цен за выбранный день.

Шаг 2: Явное указание периода в виртуальной таблице

Разберем, как изменить текст запроса для обеспечения стабильной работы. Мы должны явно передать параметр в скобках виртуальной таблицы. Это гарантирует, что СКД не будет пытаться «угадать» значение и не подставит Неопределено или объект неверного типа.

Изменим конструкцию соединения:


ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаОкончания, ) КАК ЦеныНоменклатурыСрезПоследних 

Теперь система четко понимает, что срез последних цен нужно брать на дату, хранящуюся в параметре &ДатаОкончания.

Оптимизация условий: перенос фильтров в параметры таблицы

Проанализируем еще одну критическую ошибку в исходном коде. Автор использовал условие ГДЕ ЦеныНоменклатурыСрезПоследних.ВидЦены = .... С точки зрения производительности это крайне неэффективно.

Почему это плохо: при использовании секции ГДЕ после соединения, СУБД сначала получит все последние цены по всем видам цен для всей номенклатуры из базы, присоединит их к документам, и только потом начнет «отбрасывать» лишние записи. Если в базе десятки тысяч позиций и десятки видов цен, отчет будет работать крайне медленно или вызовет переполнение памяти.

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


ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаОкончания, ВидЦены = &НужныйВидЦены) КАК ЦеныНоменклатурыСрезПоследних 

Если вид цены зависит от условий (как в примере автора с единицей измерения «мл»), рекомендуется предварительно подготовить данные во временных таблицах или использовать связи наборов данных в СКД.

Особенности объединения данных из разных документов

Посмотрим на ситуацию, когда отчет собирает данные из РеализацияТоваровУслуг и ЧекККМ через оператор ОБЪЕДИНИТЬ ВСЕ. Чтобы отчет работал корректно при указании периода, условие по дате должно стоять в каждом блоке объединения.

Рассмотрим структуру правильного запроса:


ВЫБРАТЬ ... ИЗ Документ.РеализацияТоваровУслуг.Товары 
ГДЕ Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ ... ИЗ Документ.ЧекККМ.Товары 
ГДЕ Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

Если забыть условие в одном из блоков, отчет выдаст лишние данные за весь период существования базы, что и наблюдалось у автора темы при работе в «облаке».

Различия в поведении: локальная база и «облако» (SQL-сервер)

Проанализируем, почему на локальном компьютере отчет мог работать, а на сервере выдавал ошибку или некорректные цифры. Это часто связано с типом используемой СУБД (файловая 1С против MS SQL или PostgreSQL).

Основные отличия:

  1. Обработка NULL: При ЛЕВОМ СОЕДИНЕНИИ, если цена не найдена, поле Цена будет содержать NULL. В файловой базе это иногда может автоматически преобразовываться в 0 при арифметических операциях, но в SQL-сервере это приведет к тому, что весь результат выражения станет NULL. Рекомендуем всегда использовать функцию ЕСТЬNULL(Поле, 0).
  2. Типизация пустых значений: Серверные базы данных более строго относятся к типам параметров. Там, где файловая база «проглотит» незаполненный параметр, SQL-сервер выдаст ошибку несоответствия типов.

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

← На главную