2 апр. 2013 г.

Особенности получения последних документов

Наверняка многие коллеги сталкивались с такой задачей, как получение первых/последних документов в выборке. В зависимости от необходимого результата к реализации решения можно подойти различными способами.

Разберем на примере демо-базы УТ11, найдем последние документы прихода номенклатуры по регистру "ТоварыНаСкладе". Под последним документом в контексте данной задачи может пониматься как документ с наибольшей датой документа, так и последний документ, введенный пользователем.

В ниже приведенных пакетных запросах первый запрос пакета нужен для демонстрации картины в целом, последующие запросы формируют результат.
Для одной номенклатуры все просто, нужно сделать упорядочивание по регистратору и выбрать первый документ.

ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 ТоварыНаСкладахОбороты.Регистратор КАК Регистратор,
 ТоварыНаСкладахОбороты.ВНаличииПриход КАК ВНаличииПриход
ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

УПОРЯДОЧИТЬ ПО
 Регистратор УБЫВ
 АВТОУПОРЯДОЧИВАНИЕ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ ПЕРВЫЕ 1
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,      
 ТоварыНаСкладахОбороты.Регистратор КАК Регистратор,
 ТоварыНаСкладахОбороты.ВНаличииПриход КАК ВНаличииПриход
ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

УПОРЯДОЧИТЬ ПО
 Регистратор УБЫВ
 АВТОУПОРЯДОЧИВАНИЕ 


Без автоупорядочивания сортировка произойдет без учета даты документа, по уникальному идентификатору. В этом случае, документы введенные позже приходного ордера ЦУ-33 задним числом встанут в начало выборки. Уберем "АВТОУПОРЯДОЧИВАНИЕ" из запроса и посмотрим результат.


Если воспользоваться методом получения даты создания объекта из GUID, то в первом случае 3339428b-6656-11e0-af2a-0015e9b8c48d создан 14.04.2011, во втором b2c7cfa2-6ca9-11e0-af30-0015e9b8c48d - 22.04.2011. То есть второй способ можно применять, если нужно определить последний документ прихода, введенный пользователем.

В случае, когда нужно определить последние документы для перечня номенклатуры конструкция "ВЫБРАТЬ ПЕРВЫЕ" нам уже не подходит. Поэтому, чтобы свернуть выборку по регистратору, будем использовать функцию МАКСИМУМ.

ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 ТоварыНаСкладахОбороты.Регистратор КАК Регистратор

ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, ) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

УПОРЯДОЧИТЬ ПО
 Номенклатура,
 Регистратор УБЫВ
 АВТОУПОРЯДОЧИВАНИЕ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 МАКСИМУМ(ТоварыНаСкладахОбороты.Регистратор) КАК Регистратор

ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, ) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

СГРУППИРОВАТЬ ПО
 ТоварыНаСкладахОбороты.Номенклатура

УПОРЯДОЧИТЬ ПО
 Номенклатура,
 Регистратор УБЫВ
 АВТОУПОРЯДОЧИВАНИЕ
;


Как видно из результата, функция МАКСИМУМ сворачивает выборку по GUID объекта. То есть, этот способ не подходит для случая, когда нам нужно получить последний документ, исходя из даты документа. Получать перечень номенклатуры и потом в цикле для каждой позиции получать последний документ тоже не наш вариант, замедляется быстродействие. Поэтому перепишем запрос, добавим временную таблицу, в которой свернем выборку по максимуму даты регистратора. Эту дату и будем использовать для соединения с основной выборкой. В последнем запросе так же сворачиваем выборку по максимуму регистратора, но теперь мы получим последний введенный документ с учетом последней даты документа.

ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 ТоварыНаСкладахОбороты.Регистратор КАК Регистратор,
 ТоварыНаСкладахОбороты.ВНаличииПриход КАК ВНаличииПриход
ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, ) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

УПОРЯДОЧИТЬ ПО
 Номенклатура,
 Регистратор УБЫВ
 АВТОУПОРЯДОЧИВАНИЕ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 МАКСИМУМ(ТоварыНаСкладахОбороты.Регистратор.Дата) КАК Дата
ПОМЕСТИТЬ времДата
ИЗ
 РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, ) КАК ТоварыНаСкладахОбороты
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

СГРУППИРОВАТЬ ПО
 ТоварыНаСкладахОбороты.Номенклатура
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
 ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура,
 МАКСИМУМ(ТоварыНаСкладахОбороты.Регистратор) КАК Регистратор
ИЗ
 времДата КАК времДата
  ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Обороты(, , Регистратор, ) КАК ТоварыНаСкладахОбороты
  ПО времДата.Номенклатура = ТоварыНаСкладахОбороты.Номенклатура
   И времДата.Дата = ТоварыНаСкладахОбороты.Регистратор.Дата
ГДЕ
 ТоварыНаСкладахОбороты.ВНаличииПриход > 0

СГРУППИРОВАТЬ ПО
 ТоварыНаСкладахОбороты.Номенклатура

УПОРЯДОЧИТЬ ПО
 Номенклатура
 АВТОУПОРЯДОЧИВАНИЕ 


UPD: как правильно заметили в комментариях, механизм генерации ГУИД обеспечивает только уникальность, но не возрастающую последовательность. На момент написания статьи проведенные тесты давали необходимый результат. Но гарантии, что выявленная закономерность сохранится в последующих версиях платформы, нет. Поэтому, если необходимо фиксировать момент создания документов, то лучше реализовать свой механизм. Например, с использованием регистра сведений.


6 комментариев:

  1. Анонимный16 июня 2014 г., 13:02

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

    ОтветитьУдалить
    Ответы
    1. Почему нет? В последнем запросе в случае, когда встретится два и более документа с одинаковым датой/временем, возьмется только один по МАКСИМУМ(ТоварыНаСкладахОбороты.Регистратор), иначе говоря последний введенный документ поступления на эту дату/время.

      Удалить
  2. Получается МАКСИМУМ() выбирает максимальный уникальный идентификатор, который икрементально строится на основании даты создания ссылки ?

    ОтветитьУдалить
    Ответы
    1. В общих чертах, да. По результатам, МАКСИМУМ по ссылке дает ссылку (он же УИД) на последний введенный объект.

      Удалить
    2. Этот комментарий был удален автором.

      Удалить
  3. Этот комментарий был удален автором.

    ОтветитьУдалить