Работа с прямыми запросами в 1С 7.7 через внешнюю компоненту 1С++ предоставляет огромные преимущества в скорости, но требует глубокого понимания того, как метаданные 1С транслируются в структуру таблиц SQL. Одной из самых частых проблем для разработчиков становится ошибка Недопустимое имя столбца "IDDoc" при обращении к виртуальным таблицам. В рамках этой статьи мы подробно разберем, почему возникает эта ошибка, как правильно работать с позицией документа и как корректно обращаться к ресурсам регистров в виртуальных таблицах оборотов.
Разберем ситуацию: при использовании макроса $РегистрОбороты с детализацией до документа (третий параметр макроса), SQL-запрос обращается не к физической таблице движений, а к динамически формируемому набору данных. В этом наборе данных поле IDDoc в явном виде отсутствует. Вместо него виртуальная таблица возвращает системное поле ПозицияДокумента (или Position).
Поле ПозицияДокумента представляет собой строку (или бинарные данные) длиной 23 символа, в которой закодированы дата, время и идентификатор документа. Поскольку прямая связь с журналом документов _1sjourn обычно происходит именно по IDDoc, нам необходимо «вытащить» этот идентификатор из позиции. Рассмотрим, как это сделать правильно.
Проанализируем структуру поля ПозицияДокумента. В системе 1С 7.7 IDDoc всегда занимает последние 9 символов в строке позиции. Поэтому для соединения с журналом или для вывода ссылки на документ в отчет нам нужно использовать строковую функцию SQL RIGHT. Посмотрим на примере исправленного запроса:
SELECT
RIGHT(Рег.ПозицияДокумента, 9) as [Док $Документ],
Рег.ОстатокТовараОборот as ОстатокТовара
FROM
$РегистрОбороты.ПартииТоваров(:ДатаС, :ДатаКон, Документ, , , , ) as Рег
INNER JOIN _1sjourn Жур ON RIGHT(Рег.ПозицияДокумента, 9) = Жур.IDDoc
В данном примере мы используем RIGHT(Рег.ПозицияДокумента, 9), чтобы получить чистый идентификатор документа, который успешно сопоставляется с полем IDDoc в таблице _1sjourn. Также обратите внимание на типизацию [Док $Документ] — это подсказка для 1С++, чтобы она преобразовала 9-символьный идентификатор в полноценный объект (ссылку) 1С.
Выясним еще одну причину возникновения ошибок — опечатки в псевдонимах (алиасах) таблиц. В сложных запросах с несколькими JOIN легко ошибиться в обращении к полям. Рассмотрим фрагмент кода, который вызвал затруднение у автора темы:
AND (jr.Жур BETWEEN :ДокументыДатаС~~ AND :ДатаКон~~)
Здесь допущена ошибка: используется префикс jr, хотя таблица журнала была определена под алиасом Жур. Проанализируем правильный вариант:
INNER JOIN _1sjourn Жур
ON RIGHT(Рег.ПозицияДокумента, 9) = Жур.IDDoc
AND (Жур.DATE_TIME_IDDOC BETWEEN :ДатаС~~ AND :ДатаКон~~)
Важно помнить, что в таблице _1sjourn для фильтрации по периоду лучше использовать поле DATE_TIME_IDDOC, так как оно индексировано и обеспечивает максимальную производительность. Символы ~~ после имени параметра в 1С++ преобразуют дату в специальный формат SQL, подходящий для сравнения с позицией журнала.
Перейдем к следующей распространенной ошибке: Недопустимое имя столбца "ОстатокТовараОборот". В виртуальных таблицах оборотов 1С++ автоматически формирует суффиксы для ресурсов. Если вы указали список ресурсов в параметрах макроса, то должны обращаться к ним строго определенным образом.
Для каждого числового ресурса (например, ОстатокТовара) виртуальная таблица создает три виртуальных поля:
Если SQL выдает ошибку, что поле Оборот не найдено, это может означать, что для данного регистра в метаданных или в самом запросе использование оборота ограничено. Рассмотрим ситуацию, когда автору помогла замена Оборот на Приход. Если ваша задача — увидеть конкретные движения по документу (например, сколько товара поступило по конкретной накладной), логичнее использовать именно поле Приход или Расход, так как в контексте одного документа «Оборот» может не иметь физического смысла или не поддерживаться механизмом итогов для определенных настроек регистра.
Сведем все исправления воедино. Мы исправили извлечение IDDoc, наложили правильный фильтр на журнал и обратились к существующему полю ресурса. Посмотрим, как теперь выглядит работоспособный код:
SELECT
-- Извлекаем IDDoc и типизируем как документ
RIGHT(Рег.ПозицияДокумента, 9) as [Док $Документ],
-- Используем корректный суффикс ресурса
Рег.ОстатокТовараПриход as ОстатокТовара,
Рег.ПродСтоимостьПриход as ПродСтоимость
FROM
$РегистрОбороты.ПартииТоваров(:ДатаС, :ДатаКон, Документ, ,
Контрагент = :ВыбКонтрагент AND Статус = :ВыбСтатус, ,
(ОстатокТовара, ПродСтоимость)) as Рег
INNER JOIN _1sjourn Жур ON RIGHT(Рег.ПозицияДокумента, 9) = Жур.IDDoc
WHERE
Жур.DATE_TIME_IDDOC BETWEEN :ДатаС~~ AND :ДатаКон~~
Проанализируем несколько советов, которые помогут избежать ошибок в будущем:
ПозицияДокумента) и суффиксы ресурсов. Это отличный способ получить шаблон без опечаток.: с указанием типа, например $Справочник.Контрагенты. Это гарантирует, что SQL получит правильный внутренний идентификатор (ID), а не строковое название.RIGHT(ПозицияДокумента, 9) с IDDoc иногда могут возникать проблемы с концевыми пробелами в зависимости от настроек SQL-сервера. Если соединение не отрабатывает, попробуйте обернуть поля в функцию RTRIM().WHERE) внутри макроса виртуальной таблицы (5-й параметр), а не снаружи. Это позволит SQL-серверу обработать меньше данных еще на этапе формирования выборки, что значительно ускорит отчет.Таким образом, успех при написании прямых запросов в 1С 7.7 зависит от внимательности к деталям реализации виртуальных таблиц. Помните, что IDDoc в контексте детализации до документа всегда скрыт внутри ПозицияДокумента, а ресурсы требуют явного указания типа движения через суффиксы.