При выполнении прямых SQL-запросов в 1С 7.7 с использованием внешней компоненты 1С++ разработчики часто сталкиваются с ошибкой синтаксического анализатора метаданных: «Meta name parser error: виртуальное поле не найдено». В этой статье мы разберем причины возникновения данной ошибки при работе с макросом $ПоследнееЗначение, рассмотрим правильный синтаксис его вызова и изучим альтернативный способ получения данных из таблицы периодических реквизитов _1SCONST.
Проанализируем исходный запрос, в котором возникла ошибка. Разработчик пытается получить последнее значение периодического реквизита «СерийныйНомер» для справочника «ДСП_Аппараты»:
SELECT
СпрАпп.ID КАК Ссылка,
$ПоследнееЗначение.СпрАпп.СерийныйНомер(СпрАпп.ТекЭлемент, ТекДата, 86399000) КАК СерийныйНомер
FROM
$Справочник.ДСП_Аппараты КАК СпрАпп
WHERE
СерийныйНомер = СерийникДляПоиска
Причина сбоя заключается в том, как парсер 1С++ (модуль MetaNameParser) обрабатывает макрос $ПоследнееЗначение. Данный макрос ожидает в качестве имени объекта метаданных строгое наименование справочника из конфигуратора, а не псевдоним таблицы (алиас), заданный в секции FROM.
Когда парсер видит конструкцию $ПоследнееЗначение.СпрАпп.СерийныйНомер, он ищет объект метаданных с именем СпрАпп. Поскольку такого объекта в конфигурации нет (это всего лишь псевдоним для таблицы $Справочник.ДСП_Аппараты), парсер выдает ошибку о том, что виртуальное поле не найдено.
Рассмотрим стандартный синтаксис макроса получения последнего значения периодического реквизита:
$ПоследнееЗначение.<ВидОбъекта>.<Идентификатор>(Элемент, Дата)
Для исправления ошибки заменим псевдоним таблицы СпрАпп на реальное имя вида справочника из метаданных — ДСП_Аппараты. Также передадим параметры даты и искомого значения через текстовые параметры объекта ODBCRecordSet.
Исправленный вариант прямого запроса выглядит следующим образом:
// Создаем объект запроса
Запрос = СоздатьОбъект("ODBCRecordSet");
// Задаем текст SQL-запроса с правильным макросом
ТекстЗапроса = "
|SELECT
| СпрАпп.ID КАК [Ссылка $Справочник.ДСП_Аппараты],
| $ПоследнееЗначение.ДСП_Аппараты.СерийныйНомер(СпрАпп.ID, :ТекДата) КАК СерийныйНомер
|FROM
| $Справочник.ДСП_Аппараты КАК СпрАпп
|WHERE
| $ПоследнееЗначение.ДСП_Аппараты.СерийныйНомер(СпрАпп.ID, :ТекДата) = :СерийникДляПоиска
|";
// Устанавливаем параметры
Запрос.УстановитьТекстовыйПараметр("СерийникДляПоиска", СокрЛП(СерийникДляПоиска));
Запрос.УстановитьТекстовыйПараметр("ТекДата", ТекущаяДата());
// Выполняем запрос
Результат = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
Важное примечание: Обратите внимание, что псевдоним вычисляемого поля из секции SELECT нельзя использовать напрямую в условии WHERE на уровне T-SQL. По этой причине выражение макроса дублируется в секции фильтрации или оборачивается во вложенный запрос.
Выясним, как данные периодических реквизитов хранятся в базе данных 1С 7.7. Все периодические реквизиты справочников и периодические константы находятся в единой системной таблице _1SCONST.
Основные поля таблицы _1SCONST:
OBJID — идентификатор объекта справочника, к которому относится значение.ID — внутренний идентификатор реквизита в метаданных.DATE — дата установки значения.VALUE — значение реквизита в строковом формате.Мы можем написать прямой запрос к таблице _1SCONST через объект ODBCRecordSet и вспомогательный объект MetaDataWork для получения ID реквизита.
Разберем пример кода:
рс = СоздатьОбъект("ODBCRecordSet");
Мета = СоздатьОбъект("MetaDataWork");
// Передаем дату и ID реквизита справочника
рс.УстановитьТекстовыйПараметр("ТекДата", ТекущаяДата());
рс.УстановитьТекстовыйПараметр("ИДРеквизита", Мета.ИДРеквизитаСправочника("ДСП_Аппараты", "СерийныйНомер"));
рс.УстановитьТекстовыйПараметр("НужныйСерийник", СокрЛП(СерийникДляПоиска));
// Запрос с типизацией возвращаемого значения
ТекстЗапроса = "
|SELECT TOP 10
| Константы.OBJID [Объект $Справочник.ДСП_Аппараты],
| Константы.VALUE [Значение $Строка]
|FROM
| _1SCONST AS Константы WITH (NOLOCK)
|WHERE 1=1
| AND Константы.DATE <= :ТекДата
| AND Константы.ID = :ИДРеквизита
| AND Константы.VALUE = :НужныйСерийник
|ORDER BY
| Константы.DATE DESC
|";
ТЗ = рс.ВыполнитьИнструкцию(ТекстЗапроса);
По умолчанию при обращении к полю OBJID или VALUE таблицы _1SCONST SQL Server возвращает внутренние символьные идентификаторы 1С (например, 3TF4). Для того чтобы 1С++ автоматически преобразовала эти идентификаторы в объекты 1С (ссылки на справочники или документы), необходимо применить специальную типизацию полей в квадратных скобках:
Константы.OBJID [Объект $Справочник.ДСП_Аппараты] — приводит внутренний ID к ссылке на справочник «ДСП_Аппараты».Константы.VALUE [Значение $Перечисление.ВидыОпераций] — если значением периодического реквизита является ссылка на перечисление или другой справочник.Использование явной типизации гарантирует получение готовых объектов 1С в результатах выполнения запроса вместо сырых идентификаторов базы данных.