При работе с прямыми запросами в 1С:Предприятие 7.7 (с использованием библиотеки 1С++ или класса Класс.ПрямойЗапрос) периодически возникает необходимость извлечь реквизиты подчиненного или связанного документа. В идеальной структуре метаданных реквизит основания является ссылкой на документ и хранит уникальный девятисимвольный идентификатор IDDOC. Однако на практике встречаются конфигурации, где реквизит «Основание» задан строковым типом и хранит лишь текстовый номер документа.
Рассмотрим, как правильно составить прямой SQL-запрос, чтобы связать таблицу документа с системным журналом и получить дату документа-основания по его номеру.
В физической структуре базы данных 1С 7.7 сведения о датах, номерах и статусах всех документов содержатся в единой системной таблице журнала (в запросах 1С++ к ней обращаются по псевдониму Журнал). Таблица содержит следующие ключевые поля:
IDDOC — уникальный идентификатор документа (9 символов).DOCNO — номер документа в текстовом формате.DATE — дата документа.IDDOCDEF — идентификатор вида документа.ISMARK — пометка на удаление (1 — помечен, 0 — не помечен).Если в таблице документа строковое поле з.Основание содержит номер документа-основания, то связь необходимо строить с системной таблицей Журнал по полю DOCNO.
Для связывания первичной таблицы документа с журналом связываемых документов используется повторное присоединение таблицы Журнал под отдельным псевдонимом (алиасом), например Ж1.
Проанализируем базовый пример запроса:
ТекстЗапроса = "
|select
| з.iddoc as [Номер :Документ.Заявка],
| ж.DATE as [Дата :Дата],
| з.Клиент as [Клиент :Справочник.Клиенты],
| з.Машина as [Машина :Справочник.Машины],
| з.Прицеп as [Прицеп :Справочник.Прицепы],
| з.Фирма2 as [Фирма :Справочник.Фирма],
| з.Основание,
| з.Автор as [Автор :Справочник.Сотрудники],
| ж1.DATE as [ДатаОснования :Дата]
|from Документ_Заявка as з
|INNER JOIN Журнал as ж ON з.iddoc = ж.iddoc
|LEFT JOIN Журнал as ж1 ON з.Основание = ж1.DOCNO
|where ж.DATE BETWEEN :ДатаНач AND :ДатаКон
";
Обратим внимание на выбор типа соединения: рекомендуем использовать LEFT JOIN вместо INNER JOIN. Если для какого-то документа поле з.Основание окажется пустым или номер не будет найден в журнале, при использовании INNER JOIN вся строка полностью выпадет из итоговой выборки. Использование LEFT JOIN сохраняет исходные документы в результате, а для ненайденных оснований вернет значение NULL.
В 1С 7.7 нумерация документов не всегда является сквозной и уникальной в рамках всей базы: разные виды документов (например, «Реализация» и «Поступление») могут иметь одинаковые номера DOCNO. Чтобы запрос не связывал запись с документами чужих видов, необходимо обязательно ограничивать вид документа с помощью фильтра по IDDOCDEF.
Разберем пример с указанием конкретного вида документа-основания:
ТекстЗапроса = "
|select
| з.iddoc as [Документ :Документ.Заявка],
| ж.DATE as [Дата :Дата],
| з.Основание,
| ж1.DATE as [ДатаОснования :Дата]
|from Документ_Заявка as з
|INNER JOIN Журнал as ж ON з.iddoc = ж.iddoc
|LEFT JOIN Журнал as ж1 ON з.Основание = ж1.DOCNO
| AND ж1.IDDOCDEF = $ВидДокумента.Реализация
|where ж.DATE BETWEEN :ДатаНач AND :ДатаКон
";
В данном примере конструкция $ВидДокумента.Реализация подставляет внутренний идентификатор вида документа, гарантируя точный поиск нужного документа в журнале.
При использовании текстового поиска по номерам документов важно учитывать следующие факторы:
DOCNO имеют фиксированную длину и дополняются ведущими нулями или пробелами (например, "0000000123"). Если строка в реквизите з.Основание записана без выравнивания по длине номера, прямое равенство в SQL-запросе не сработает. В таком случае номер перед передачей в запрос необходимо отформатировать средствами встроенного языка 1С.RTRIM, LTRIM, RIGHT) непосредственно в условии соединения ON отключает использование индексов по полю DOCNO, что приводит к сканированию всей таблицы журнала (Table Scan) и существенному замедлению работы.IDDOC, что обеспечит максимальную скорость выполнения.