Как получить реквизиты регистра в прямом запросе 1С 7.7 через ODBCRecordset?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При переходе на использование прямых SQL-запросов в среде 1С:Предприятие 7.7 с помощью внешней компоненты 1С++, разработчики часто сталкиваются с трудностями при получении данных, которые выходят за рамки стандартных измерений и ресурсов. Одной из таких проблем является извлечение реквизитов регистра. В отличие от стандартного метода ВыгрузитьДвижения(), прямые запросы требуют четкого понимания структуры хранения данных в SQL-таблицах. Рассмотрим подробно, как правильно составить запрос для решения этой задачи.

Различие между виртуальными и физическими таблицами

Для начала проанализируем, почему стандартные метатеги, такие как $РегистрОстатки или $РегистрОбороты, не возвращают реквизиты. В архитектуре 1С 7.7 данные регистров распределены по разным физическим таблицам:

  1. Таблица итогов (RG...): Здесь хранятся агрегированные данные (остатки) в разрезе измерений. Реквизитов здесь нет по определению, так как реквизит относится к конкретному событию (движению), а не к итоговому состоянию. К этой таблице обращается метатег $РегистрОстатки.
  2. Таблица движений (RA...): Это «сырой» лог всех записей, произведенных документами. Именно здесь хранятся значения измерений, ресурсов и реквизитов. К этой таблице обращается метатег $Регистр.ИмяРегистра.

Выясним причину ошибки автора темы. При использовании конструкции $РегистрОстатки.Партии(,,,,) компонента 1С++ генерирует сложный подзапрос к таблице итогов. Поскольку реквизиты не являются частью итогов, они просто отсутствуют в выборке. Чтобы их получить, нам нужно обращаться напрямую к таблице движений.

Правильный синтаксис обращения к реквизитам

Разберем по шагам, как получить данные из таблицы движений. Важнейшим моментом здесь является синтаксис метатега. В отличие от виртуальных таблиц (остатков и оборотов), обращение к физической таблице $Регистр не требует скобок, так как это не функция, а прямое указание на имя таблицы в базе данных.

Рассмотрим пример правильного кода для получения всех полей регистра, включая реквизиты:


ТекстЗапроса = "
|SELECT
|    *
|FROM
|    $Регистр.Партии AS рег
|";
Recordset.ВыполнитьИнструкцию(ТекстЗапроса, ТаблицаРезультатов);

Обратите внимание: если вы добавите скобки после $Регистр.Партии(), SQL-сервер выдаст ошибку, так как попытается интерпретировать имя таблицы как хранимую функцию, коей она не является.

Особенности работы с данными в таблице RA

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

1. Типизация ссылочных полей. Все ссылки на справочники и документы хранятся в виде 13-символьных строк в кодировке Base36. Чтобы 1С++ автоматически преобразовала их в объекты (например, СправочникСсылка), рекомендуется использовать типизацию в самом SQL-запросе через метатег $Тип или конструкцию описания полей.

2. Связь с датой документа. В таблице движений (RA) отсутствует поле с датой. Есть только поле IDDOC (идентификатор документа). Чтобы отфильтровать движения по периоду или получить дату совершения операции, необходимо выполнить соединение (JOIN) с таблицей системного журнала _1SJOURN.

Рассмотрим пример запроса с получением даты и типизацией товара:


ТекстЗапроса = "
|SELECT
|    Журнал.DATE_TIME_IDDOC as [ДатаДок],
|    $Рег.Товар as [Товар $Справочник.Товары],
|    $Рег.Количество as [Количество],
|    $Рег.Сумма as [Сумма],
|    $Рег.НомерСкидочнойКарты as [СкидочнаяКарта]
|FROM
|    $Регистр.Партии AS Рег
|INNER JOIN
|    _1SJOURN AS Журнал ON Журнал.IDDOC = Рег.IDDOC
|WHERE
|    Журнал.DATE_TIME_IDDOC BETWEEN :НачДата AND :КонДата~
|";
Recordset.УстПараметр("НачДата", ВыбНачДата);
Recordset.УстПараметр("КонДата", ВыбКонДата);
Таблица = Recordset.ВыполнитьИнструкцию(ТекстЗапроса);

Почему нельзя использовать SELECT * в реальных задачах?

Посмотрим на пример из обсуждения, где автор использует SELECT *. Хотя это помогло ему увидеть наличие полей в Management Studio, в реальной разработке это считается плохой практикой по нескольким причинам:

Использование типизации для реквизитов

Если ваш реквизит является ссылкой на справочник, крайне важно указать это в запросе. Например, если реквизит НомерСкидочнойКарты — это ссылка на справочник ДисконтныеКарты, запрос должен выглядеть так:


|SELECT
|    $Рег.НомерСкидочнойКарты as [Карта $Справочник.ДисконтныеКарты]
|FROM
|    $Регистр.Партии AS Рег

В этом случае в объекте ТаблицаРезультатов в соответствующей колонке будут лежать уже готовые объекты 1С, с которыми можно работать методами встроенного языка (например, получать их атрибуты через точку).

Резюме и рекомендации

Подведем итог нашему анализу. Чтобы успешно извлекать реквизиты регистров в 1С 7.7 через 1С++:

  1. Всегда используйте метатег $Регистр.ИмяРегистра (физическая таблица движений).
  2. Никогда не ставьте скобки после имени регистра при обращении к $Регистр.
  3. Для фильтрации по дате или получения времени движения обязательно делайте INNER JOIN с таблицей _1SJOURN по полю IDDOC.
  4. Явно перечисляйте нужные поля и используйте метатеги типизации ($Справочник, $Документ), чтобы упростить дальнейшую обработку данных.

Следуя этим правилам, вы сможете эффективно использовать мощь прямых SQL-запросов, сохраняя при этом удобство работы с объектами метаданных 1С.

← На главную