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

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

При работе с 1С:Предприятие 7.7 и компонентой 1++ часто возникает задача получения истории значений периодических реквизитов напрямую из базы данных SQL. Стандартный язык запросов 1С 7.7 не всегда справляется с большими объемами данных, поэтому разработчики пишут прямые запросы. Рассмотрим подробнее, как правильно получить аналог платформенного Среза Первых или Среза Последних, и разберем синтаксис, который поможет избавиться от жестко заданных внутренних идентификаторов.

Структура хранения периодических реквизитов в 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() позволяет пронумеровать строки внутри заданных групп.

Алгоритм действий будет следующим:

  1. Разбиваем все записи таблицы _1SCONST на своеобразные "окна" по внутреннему идентификатору объекта с помощью конструкции PARTITION BY const.objid.
  2. Внутри каждого окна нумеруем строки по хронологии. Для Среза Первых сортируем по возрастанию (ASC): ORDER BY const.date ASC, const.time ASC, const.docid ASC, const.row_id ASC.
  3. Если нам нужен аналог Среза Последних (функция платформы $ПоследнееЗначение), меняем сортировку дат и времени на убывающую (DESC).
  4. Внешним запросом отбираем только те строки, у которых вычисленный номер строки равен единице.

Такой подход работает во много раз быстрее подзапросов и позволяет получить данные для целой таблицы значений или временной таблицы в рамках одного прохода.

Особенности ручного изменения истории

При написании сортировки для среза важно учитывать еще одну архитектурную особенность 1С 7.7. Периодический реквизит может быть установлен двумя способами: проведенным документом или вручную из пользовательского интерфейса (формы элемента справочника).

Выясним причину, почему это важно для сортировки. При ручной установке в поле docid записывается «пустое» значение (состоящее из нулей или пробелов), а время часто обнуляется или устанавливается платформой на самый конец дня. Эти записи всегда будут иметь специфический приоритет при сортировке перед записями, которые были сделаны документами-регистраторами за ту же самую дату. Поэтому включение в сортировку полей time, docid и row_id является строго обязательным для получения корректного, детерминированного результата, полностью совпадающего со штатным поведением платформы 1С.

← На главную