При переходе на использование прямых SQL-запросов с помощью внешней компоненты 1С++ в среде 1С:Предприятие 7.7 разработчики нередко сталкиваются с ошибками компилятора платформы или метапарсера компоненты. Рассмотрим наиболее частые причины возникновения сообщений «Переменная не определена», «Ожидается выражение» и сбоев синтаксиса SQL-сервера вида State 42000, native 170, а также разберем по шагам, как правильно конструировать запросы к базе данных.
Проанализируем ситуацию, когда при запуске программного модуля платформа выдает каскад ошибок:
Ожидается выражение
Слишком много фактических параметров
Переменная не определена (ПоступлениеТоваров)
Неопознанный оператор
Выясним причину такого поведения. Компилятор встроенного языка 1С 7.7 требует строгого синтаксического оформления многострочных строковых литералов. Если текст SQL-запроса вставлен в модуль напрямую, без кавычек или без знака переноса строки |, платформа пытается интерпретировать SQL-код как команды 1С. В результате имена таблиц принимаются за необъявленные переменные, а запятые в операторе SELECT — за параметры несуществующих процедур.
Посмотрим на пример корректного формирования строки запроса во встроенном языке:
ТекстЗапроса = "
|SELECT
| ПоступлениеТоваров.IDDOC [Док $Документ.ПоступлениеТоваров],
| $ПоступлениеТоваров.ВидПоступления [ВидПоступления $Перечисление.ВидыПоступления]
|FROM
| $Документ.ПоступлениеТоваров AS ПоступлениеТоваров With (NOLOCK)
|INNER JOIN
| _1SJOURN AS Журнал With (NOLOCK) ON ПоступлениеТоваров.IDDOC = Журнал.IDDOC
|WHERE
| Журнал.Date_Time_IDDoc BETWEEN :ДатаНач AND :ДатаКон~
|";
Разберем следующую частую проблему. При выполнении запроса СУБД возвращает ошибку:
State 42000, native 170, message [Microsoft][ODBC SQL Server Driver][SQL Server]Line 5: Incorrect syntax near '&'.
Рассмотрим подробнее механизм работы метапарсера 1С++. Для автоматического разыменования идентификаторов метаданных конфигурации (преобразования понятных названий реквизитов и таблиц во внутренние имена SQL, такие как DH1234, DT1234, SP5678) используется строго определенный префикс — знак доллара $.
Если в тексте запроса случайно указать символ & вместо $ (например, &ПоступлениеТоваровСтроки.МПЗ), метапарсер пропускает эту конструкцию без трансляции. В итоге в Microsoft SQL Server отправляется сырой символ &, который в данном контексте является недопустимым синтаксическим оператором.
Разберем по шагам правила разыменования объектов:
$Документ.ИмяДокумента или $Справочник.ИмяСправочника.$ДокументСтроки.ИмяДокумента.$, например $ПоступлениеТоваровСтроки.МПЗ или $ПоступлениеТоваров.ВидПоступления.$Перечисление.ИмяПеречисления.ИмяЗначения.Проанализируем тонкости хранения общих реквизитов в базе данных 1С 7.7. Физическое расположение реквизита в таблицах SQL напрямую зависит от его настроек в конфигураторе:
_1SJOURN. Обращение в запросе должно происходить через псевдоним таблицы журнала: Журнал.$ОбщийРеквизит.ИмяРеквизита.DH*). Обращаться к нему следует через псевдоним таблицы документа: ПоступлениеТоваров.$ОбщийРеквизит.ИмяРеквизита.Объединим разобранные правила и посмотрим на правильный пример прямого запроса для выборки строк документа с отбором по журналу:
ТекстЗапроса = "
|SELECT
| ПоступлениеТоваров.IDDOC [Док $Документ.ПоступлениеТоваров],
| Журнал.$ОбщийРеквизит.обКонтрагент [Поставщик $Справочник.Контрагенты],
| Журнал.$ОбщийРеквизит.обКомитент [Комитент $Справочник.Контрагенты],
| $ПоступлениеТоваровСтроки.МПЗ [МПЗ $Справочник.МПЗ],
| Журнал.$ОбщийРеквизит.ДокументОснование [ДокОснование $Документ],
| $ПоступлениеТоваровСтроки.СтавкаНДС [Ставка $Справочник.СтавкиНДС]
|FROM
| $Документ.ПоступлениеТоваров AS ПоступлениеТоваров With (NOLOCK)
|INNER JOIN
| $ДокументСтроки.ПоступлениеТоваров AS ПоступлениеТоваровСтроки With (NOLOCK)
| ON ПоступлениеТоваров.IDDOC = ПоступлениеТоваровСтроки.IDDOC
|INNER JOIN
| _1SJOURN AS Журнал With (NOLOCK)
| ON ПоступлениеТоваров.IDDOC = Журнал.IDDOC
|INNER JOIN
| $Справочник.МПЗ AS МПЗ With (NOLOCK)
| ON $ПоступлениеТоваровСтроки.МПЗ = МПЗ.ID
|WHERE
| Журнал.Date_Time_IDDoc BETWEEN :ДатаНач AND :ДатаКон~
| AND Журнал.ISMARK = 0
| AND $ПоступлениеТоваров.ВидПоступления <> $Перечисление.ВидыПоступления.ВозвратнаяТара
| AND $ПоступлениеТоваров.ВидПоступления <> $Перечисление.ВидыПоступления.ВычетНДС
| AND (ПоступлениеТоваров.$ОбщийРеквизит.Комментарий LIKE '%кредит-нота%'
| OR Журнал.$ОбщийРеквизит.ДокументОснование <> $ПустоеЗначение.Документ)
|";
Важные рекомендации:
:ДатаКон~ — метапарсер 1С++ автоматически дополнит дату до конца суток (23:59:59.999), что исключает необходимость вызова медленных функций CAST и LEFT по полю Date_Time_IDDoc и задействует кластерный индекс.' 0 0 ') рекомендуется использовать специальный макрос $ПустоеЗначение.Документ или $ПустойИД13.Возврат) не попадали в строковый литерал без комментария.