СрезПоследних без регистра
Возникла тут задача поиска последних документов по определенной аналитике. Регистр ради такого создавать как-то странно. Но в памяти записано, что без него почему-то сложно. Давайте же, наконец, разберемся...
Для воспроизводимости примеров буду искать последние реализации по контрагентам.
Выбрать Контрагент, Максимум(Ссылка) Из Документ.РеализацияТоваровУслуг Сгруппировать по Контрагент
И оно сработало. Выборочные проверки удивительным образом убеждают в правильности. Неужели нам врали? Или может платформу допилили до того, что поиск максимума среди документов ожидаемо учитывает хронологию?
Проверим правильность результата тоже запросом:
Выбрать * Из ( Выбрать Контрагент, Количество(Ссылка) Как Количество, Минимум(Ссылка) Как Первый, Максимум(Ссылка) Как Последний Из Документ.РеализацияТоваровУслуг Где Контрагент в ( Выбрать Контрагент из Документ.РеализацияТоваровУслуг Сгруппировать по Контрагент Имеющие Количество(*) > 1 ) Сгруппировать по Контрагент ) Как Подзапрос Где Первый.Дата > Последний.Дата
И борода! Ошибок конечно меньше половины, но они есть и их много. Значит, простое решение в лоб не годится. Жаль.
Гуглим, яндексим... Большинство убеждено в таком подходе:
Выбрать Последние.Контрагент, Последние.Ссылка Из Документ.РеализацияТоваровУслуг Как Последние Внутреннее Соединение ( Выбрать Контрагент, Максимум(Дата) Как МаксДата Из Документ.РеализацияТоваровУслуг Сгруппировать По Контрагент ) Как Даты По Последние.Контрагент = Даты.Контрагент и Последние.Дата = Даты.МаксДата
Вроде все логично, оно работает. Даже проверять не надо. Ура! Но одинокие робкие голоса в форумах задают неудобный вопрос: что будет если два документа с одним контрагентом умещаются в одну секунду. А будет плохо. Соединение, как и положено, выведет обе записи. Тут можно поразмышлять о том, что такое последний документ, если их два в секунду. Например, в моей задаче такое почти невозможно, а уж если произойдет, вполне достаточно любого из двух. Но когда выводятся оба, это некрасиво.
К сожалению к ошибке приводит такой напрашивающийся код:
Выбрать Максимум(МоментВремени) из Документ.РеализацияТоваровУслуг
А что если применить возможность новых платформ по преобразованию к строке, ведь нас при одинаковом времени вполне устроит больший номер:
Максимум(Дата) заменим на Максимум(Строка(Дата) + Номер)
Совсем ерунда, потому что "02.01" больше чем "01.02" (второе января позже первого февраля). Эх.
И тут приходит решение. В строку надо преобразовывать разность в секундах относительно какой-то очень старой даты, например, как принято в unix-системах, 1970 года:
Выбрать Последние.Контрагент, Последние.Ссылка Из Документ.РеализацияТоваровУслуг Как Последние Внутреннее Соединение ( Выбрать Контрагент, Максимум(Строка(РазностьДат(ДатаВремя(1970,1,1), Дата, Секунда)) + Номер) Как МаксДатаНомер Из Документ.РеализацияТоваровУслуг Сгруппировать По Контрагент ) Как Даты По Последние.Контрагент = Даты.Контрагент и Строка(РазностьДат(ДатаВремя(1970,1,1), Последние.Дата, Секунда)) + Номер = Даты.МаксДатаНомер
Наконец-то. Задвоение ушло. Все работает как надо.
Вывод как всегда прост, не верьте никаким советам в блогах и форумах, в том числе моим. Всегда проверяйте, ищите ошибки при крайних (граничных) значениях. Не внедряйте в работу чужое чуть-чуть некорректное. Потратьте время, разберитесь, найдите правильное решение именно вашей задачи и только тогда - в продакшн.