При работе с 1С:Предприятие 7.7 и компонентой 1++ часто возникает задача получения истории значений периодических реквизитов напрямую из базы данных SQL. Стандартный язык запросов 1С 7.7 не всегда справляется с большими объемами данных, поэтому разработчики пишут прямые запросы. Рассмотрим подробнее, как правильно получить аналог платформенного Среза Первых или Среза Последних, и разберем синтаксис, который поможет избавиться от жестко заданных внутренних идентификаторов.
Для начала проанализируем, как физически хранятся данные. В 1С 7.7 значения всех периодических реквизитов справочников и история констант записываются в одну общую системную таблицу — _1SCONST. При написании запроса к этой таблице начинающие разработчики часто пытаются фильтровать данные по жестко заданному числовому идентификатору реквизита. Например, условие может выглядеть как const.id = 114. Такой подход работает, но делает запрос непереносимым: при выгрузке и загрузке в другую базу или при изменении структуры метаданных внутренний ID реквизита может измениться, и запрос сломается.
Чтобы этого избежать, компонента 1++ предоставляет специальный метапарсер. Вместо конкретных чисел мы можем использовать конструкцию вида $ИсторияРеквизита.ВидСправочника.ИмяРеквизита. При выполнении кода парсер 1++ автоматически подменит эту строку на правильный ID из словаря метаданных. Посмотрим на правильный пример обращения:
const.id = $ИсторияРеквизита.Цены.Цена
Разберем по шагам базовый пример из практики. Если нам нужно получить самое первое значение реквизита только для одного конкретного элемента справочника, можно использовать конструкцию SELECT TOP 1. При этом крайне важно помнить о преобразовании типов. Поле VALUE в таблице _1SCONST всегда имеет строковый тип, даже если в конфигураторе реквизит задан как «Число». Мы должны использовать оператор CAST для приведения строки к числу, иначе математические операции или сортировка будут работать некорректно.
Посмотрим на пример такого запроса:
select top 1
cast(const.value as numeric(18, 4)) as ПервоеЗначение
from
_1sconst as const (nolock)
where
const.id = $ИсторияРеквизита.Цены.Цена and
const.objid = VT.Товар and
const.date > '20200930'
order by
const.date ASC,
const.time ASC,
const.docid ASC,
const.row_id ASC
Этот запрос отлично отработает для одной позиции. Однако термин «Срез» обычно подразумевает получение данных сразу для списка объектов (целой группы номенклатуры или списка товаров в документе). Если мы попытаемся применить SELECT TOP 1 к списку без сложных коррелированных подзапросов, вернется лишь одна запись для какого-то одного случайного товара.
Так как компонента 1++ позволяет использовать весь синтаксис MS SQL Server, полноценный срез для множества объектов гораздо эффективнее делать через оконные функции. Оконная функция ROW_NUMBER() позволяет пронумеровать строки внутри заданных групп.
Алгоритм действий будет следующим:
_1SCONST на своеобразные "окна" по внутреннему идентификатору объекта с помощью конструкции PARTITION BY const.objid.ASC): ORDER BY const.date ASC, const.time ASC, const.docid ASC, const.row_id ASC.$ПоследнееЗначение), меняем сортировку дат и времени на убывающую (DESC).Такой подход работает во много раз быстрее подзапросов и позволяет получить данные для целой таблицы значений или временной таблицы в рамках одного прохода.
При написании сортировки для среза важно учитывать еще одну архитектурную особенность 1С 7.7. Периодический реквизит может быть установлен двумя способами: проведенным документом или вручную из пользовательского интерфейса (формы элемента справочника).
Выясним причину, почему это важно для сортировки. При ручной установке в поле docid записывается «пустое» значение (состоящее из нулей или пробелов), а время часто обнуляется или устанавливается платформой на самый конец дня. Эти записи всегда будут иметь специфический приоритет при сортировке перед записями, которые были сделаны документами-регистраторами за ту же самую дату. Поэтому включение в сортировку полей time, docid и row_id является строго обязательным для получения корректного, детерминированного результата, полностью совпадающего со штатным поведением платформы 1С.