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

```1c
    Процедура УстановитьДатыУстановокЦен(ТаблицаТоваров)

    ТабТо = ТаблицаТоваров.Скопировать(,"Номенклатура");
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | ЦеныНоменклатурыСрезПоследних.Номенклатура,
    | ЦеныНоменклатурыСрезПоследних.Период
    |ИЗ
    | РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
    | ,
    | ТипЦен = &ТипЦен
    | И Номенклатура В (&Номенклатура)) КАК ЦеныНоменклатурыСрезПоследних";

    Запрос.УстановитьПараметр("Номенклатура", ТабТо);
    Запрос.УстановитьПараметр("ТипЦен", ТипЦены);

    ТЗДатыЦен = Запрос.Выполнить().Выгрузить();
    КонецПроцедуры
```

Часто, документ устанавливает цену, равную установленной ранее цене (равную действующей цене). В этом случае, ценник на печать не выводится. Однако, затем среди кассиров происходят разборки, для установления и поругания того, кто не распечатал ценник. В ценнике же печатается дата последней установки цены номенклатуры, а не дата когда цена впервые (без прерывания) была установлена равной текущей.
Прошу помочь составить запрос для получения требуемой даты.
Единственное, что пока сделал

```1c
    ВЫБРАТЬ
    ЦеныНоменклатурыСрезПервых.Номенклатура,
    ЦеныНоменклатурыСрезПервых.Период,
    ЦеныНоменклатурыСрезПервых.Цена
    ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПервых(
    ,
    ТипЦен = &ТипЦен
    И Номенклатура В (&Номенклатура)
    И Цена В
    (ВЫБРАТЬ
    ЦеныНоменклатурыСрезПоследних.Цена
    ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ТипЦен = &ТипЦен
    И Номенклатура В (&Номенклатура)) КАК ЦеныНоменклатурыСрезПоследних)) КАК ЦеныНоменклатурыСрезПервых
```

Однако , этот код показывает цену, которая была задолго до нужной даты (цена менялась после этого, и снова стала равной выведенной дате). И в таблице значений (используется в качестве параметра) будет множество дат, весьма вероятно, то цены перепутаются между разной номенклатуры. Не хочется делать запрос в цикле, или обращаться к основной таблице регистра сведений.
---
1. Выбираем максимальный период по номенклатуре, когда цена не равна цене среза последних.
2. Выбираем минимальный период, который больше максимального из п.1
---
Предыдущее значение и дату в 1С найти просто, но от этого конечно воротит :-)

1. Соединяете таблицу саму с собой и находите для каждой даты максимальную дату, но меньшую текущей. В вашей задаче можно не саму с собой соединять, а к отфильтрованной таблице цеплять все движения. Максимальная дата это и есть предыдущая дата.
2. К полученной таблице: <Номенклатура>, <дата цены>, <цена>, <предыдущая дата> необходимо ещё раз прицепить все движения по: номенклатура, предыдущая дата и вытащить от туда предыдущую цену.
В итоге у вас получается таблица: <Номенклатура>, <дата цены>, <цена>, <предыдущая дата>, <предыдущая цена>

Далее я так понимаю всё понятно.
---
у меня такой запрос получился

```1c
    выбрать //первые 1000
    Таб.Номенклатура,
    таб.Цена,
    таб.Период
    Поместить Пром
    из
    регистрСведений.ЦеныНоменклатуры.СрезПоследних(,ВидЦены = &ВидЦены) таб
    //где
    //Таб.ВидЦены = &ВидЦены
    //и Год(таб.Период) = 2022
    //упорядочить по
    //Таб.Номенклатура
    ;
    выбрать
    пром.Номенклатура,
    Максимум(таб.Период) как Период
    Поместить ПромМакс
    из пром
    левое соединение регистрСведений.ЦеныНоменклатуры таб
    по Таб.ВидЦены = &ВидЦены
    и Таб.Номенклатура = Пром.Номенклатура
    и Таб.Цена <> Пром.Цена
    и Таб.Период < Пром.Период
    где
    таб.Период есть не null
    сгруппировать по
    пром.Номенклатура
    ;

    выбрать
    пром.Номенклатура,
    Минимум(таб.Период) как ПериодДо
    Поместить ПромМин
    из проммакс пром
    левое соединение регистрСведений.ЦеныНоменклатуры таб
    по Таб.ВидЦены = &ВидЦены
    и Таб.Номенклатура = Пром.Номенклатура
    и Таб.Период > Пром.Период
    где
    таб.Период есть не null
    сгруппировать по
    пром.Номенклатура
    ;

    Выбрать
    пром.*,
    таб.ПериодДо
    из пром
    левое соединение ПромМин таб
    по Таб.Номенклатура = Пром.Номенклатура

    где
    Пром.Период <> таб.ПериодДо

    упорядочить по
    пром.Номенклатура
```
---
В ценнике же печатается дата последней установки цены номенклатуры, а не дата когда цена впервые (без прерывания) была установлена равной текущей.

Не совсем понятно объяснение, т.к. СрезПоследних дает именно последнюю дату установки цены

Вы хотите получить дату предыдущей установленной цены?
---
Условие номенклатура и тип цен, СрезПоследних всегда даёт последнюю цену, требуемого типа.
---
так, а вам нужна дата установки предыдущей цены?

Какой скрытый смысл устанавливать одинаковую цену разными датами?
---
ТСу нужна дата, когда текущую цену установили. Типа 1 марта поставили 500 рублей, потом 2 и 3 марта тоже поставили цену 500 рублей. Нужно получить дату 1 марта.
(1) Я могу ошибаться конечно, но в типовых вроде в таком случае вообще движение по регистрам цен не делается, если цена не поменялась, и задача автоматически решается. Может вам тоже в эту сторону посмотреть вместо того, чтобы извращаться с запросами?
---
Ждем ответа ТС, по какой причине устанавливаются одинаковые цены разными датами.
---
Так исторически сложилось.
Как сказал 1с-ник, который работал до меня, он спросил у 1с-ник, который работал за 2 человека до него: "а почему в конфигурации всё вот так вот?". Пращур сказал, что так было уже до него.
---
1. Выбираем максимальный период по номенклатуре, когда цена не равна цене среза последних.
2. Выбираем минимальный период, который больше максимального из п.1
---
Придётся обращаться к основной таблице регистра?
---
Да, придётся.
---
еще как вариант подправить Установку цен, что бы этот документ не писал цену в регистр если она не изменялась!
(место за одно сэкономите)
---
вангую, там какая-то обработка загружает/устанавливает цены, несмотря на их историю.
---
если она не изменяласьБессмыслено. Таже самая ситуация будет возникать в других случаях:

Док1, 1 апреля 100 рублей
Док2, 2 апреля, 200 рублей
Док3. 3 апреля, 100 рублей

Удаляем Док2 и все. Ну и вообще при работе задним/будущим числом все поплывет.
---
на сам регистр, в событие ПередЗаписью, добавил условие проверки/отсеивания всего того что не изменилось!
---
В чем сложность-то?
Для каждой цены равной текущей (текущая цена сама себе тоже равна) находишь предыдущую цену. Там где цена была другой тебя и интересует. Находишь среди них максимальную. Ну, собственно тебе не цена нужна, а дата установки. Усё.
---
Не понял твой комментарий, напиши, пожалуйста, подробней.
---
Как тут ещё подробнее. У тебя таблица из номенклатуры и цены текущей. Это фильтр. Для всех движений цены по этому фильтру находишь предыдущее значение. Предыдущее значение ищется по всем движениям без фильтра.
Как найти предыдущее значение думаю нет сложностей. В стандартном SQL это функция LAG(), в 1С это несколько джоинов.
Далее берешь только те, где цена НЕ совпадает. Среди них находишь максимальную дату. Усё.

Если бы 1С поддерживала рекурсивные запросы как все СУБД, которые 1С использует, то было бы ещё проще.
---
Как найти предыдущее значение думают нет сложностей. В стандартном SQL это функция LAG(), в 1С это несколько джоинов.

У меня весь вопрос про то, как найти предыдущее значение. Период, когда текущая цена установлена впервые (без перерыва).
---
У меня весь вопрос про то, как найти предыдущее значение

Есть ещё проще способ найти предыдущую запись в 1С. Но я не помню с какого релиза платформы АвтоНомерЗаписи() в 1С появился. У вас 16-й. Достаточно старый.

Если у вас row_number() уже доступна, то нумеруйте все записи.
Укажите ВЫБРАТЬ ПЕРВЫЕ 999...99 и УПОРЯДОЧИТЬ ПО номенклатура, период.

В 1С, с какого-то перепуга, нельзя просто пронумеровать записи, указав требуемую сортировку, не указав SELECT TOP (MS SQL) или SELECT LIMIT (PsgSQL). Откуда они это придумали не знаю, но это так. В СУБД таких ограничений нет.

Далее соединяете таблицу саму с собой по условию WHERE т1.номенклатура = т2.номенклатура and т1.нпп = т2.нпп+1
Собственно всё.
---
В СУБД таких ограничений нетТы все время, ненавязчиво так, забываешь про файловую базу. То, что она тебе лично не нужна, не делает её менее востребованной.
---
Предыдущее значение и дату в 1С найти просто, но от этого конечно воротит :-)

1. Соединяете таблицу саму с собой и находите для каждой даты максимальную дату, но меньшую текущей. В вашей задаче можно не саму с собой соединять, а к отфильтрованной таблице цеплять все движения. Максимальная дата это и есть предыдущая дата.
2. К полученной таблице: <Номенклатура>, <дата цены>, <цена>, <предыдущая дата> необходимо ещё раз прицепить все движения по: номенклатура, предыдущая дата и вытащить от туда предыдущую цену.
В итоге у вас получается таблица: <Номенклатура>, <дата цены>, <цена>, <предыдущая дата>, <предыдущая цена>

Далее я так понимаю всё понятно.
---
у меня такой запрос получился

```1c
    выбрать //первые 1000
    Таб.Номенклатура,
    таб.Цена,
    таб.Период
    Поместить Пром
    из
    регистрСведений.ЦеныНоменклатуры.СрезПоследних(,ВидЦены = &ВидЦены) таб
    //где
    //Таб.ВидЦены = &ВидЦены
    //и Год(таб.Период) = 2022
    //упорядочить по
    //Таб.Номенклатура
    ;
    выбрать
    пром.Номенклатура,
    Максимум(таб.Период) как Период
    Поместить ПромМакс
    из пром
    левое соединение регистрСведений.ЦеныНоменклатуры таб
    по Таб.ВидЦены = &ВидЦены
    и Таб.Номенклатура = Пром.Номенклатура
    и Таб.Цена <> Пром.Цена
    и Таб.Период < Пром.Период
    где
    таб.Период есть не null
    сгруппировать по
    пром.Номенклатура
    ;

    выбрать
    пром.Номенклатура,
    Минимум(таб.Период) как ПериодДо
    Поместить ПромМин
    из проммакс пром
    левое соединение регистрСведений.ЦеныНоменклатуры таб
    по Таб.ВидЦены = &ВидЦены
    и Таб.Номенклатура = Пром.Номенклатура
    и Таб.Период > Пром.Период
    где
    таб.Период есть не null
    сгруппировать по
    пром.Номенклатура
    ;

    Выбрать
    пром.*,
    таб.ПериодДо
    из пром
    левое соединение ПромМин таб
    по Таб.Номенклатура = Пром.Номенклатура

    где
    Пром.Период <> таб.ПериодДо

    упорядочить по
    пром.Номенклатура
```
---
Действительно, ваш запрос работает спасибо!

```1c
    ВЫБРАТЬ
    таб.Номенклатура,
    таб.Цена,
    таб.Период
    ПОМЕСТИТЬ Пром
    ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
    ,
    ТипЦен = &ВидЦены
    И Номенклатура В (&Номенклатура)) КАК таб
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    пром.Номенклатура,
    МАКСИМУМ(таб.Период) КАК Период
    ПОМЕСТИТЬ ПромМакс
    ИЗ
    Пром КАК пром
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК таб
    ПО (таб.ТипЦен = &ВидЦены)
    И (таб.Номенклатура = пром.Номенклатура)
    И (таб.Цена <> пром.Цена)
    И (таб.Период < пром.Период)
    ГДЕ
    таб.Период ЕСТЬ НЕ NULL

    СГРУППИРОВАТЬ ПО
    пром.Номенклатура
    ;

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

    СГРУППИРОВАТЬ ПО
    пром.Номенклатура
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    пром.Номенклатура,
    пром.Цена,
    пром.Период,
    таб.ПериодДо
    ИЗ
    Пром КАК пром
    ЛЕВОЕ СОЕДИНЕНИЕ ПромМин КАК таб
    ПО (таб.Номенклатура = пром.Номенклатура)
    ГДЕ
    пром.Период <> таб.ПериодДо

    УПОРЯДОЧИТЬ ПО
    пром.Номенклатура
```
---
Ниже набросал запрос на SQLite, который находит для каждой номенклатуры на входе фактическую дату установки последней цены.
Тут я не стал срез собирать и по нему фильтры устраивать. Сделал просто для всех номенклатур и только поиск этой фактической даты установки последней цены.
Запрос крайне короткий и понятный.

```1c
    WITH vt_data as (
    sel ect 'Номенклатура1' as p, strftime('2022-01-17T00:00:00.000') as d, 100 as c
    UNI ON ALL sel ect 'Номенклатура1', strftime('2022-01-19T00:00:00.000'), 90
    UNI ON ALL select 'Номенклатура1', strftime('2022-01-207T00:00:00.000'), 100
    UNI ON ALL select 'Номенклатура1', strftime('2022-01-21T00:00:00.000'), 110
    UNI ON ALL sel ect 'Номенклатура1', strftime('2022-01-23T00:00:00.000'), 100
    UNION ALL sel ect 'Номенклатура1', strftime('2022-01-27T00:00:00.000'), 100
    UNION ALL sel ect 'Номенклатура2', strftime('2022-01-17T00:00:00.000'), 200
    UNION ALL sel ect 'Номенклатура2', strftime('2022-01-18T00:00:00.000'), 220
    UNION ALL sel ect 'Номенклатура2', strftime('2022-01-19T00:00:00.000'), 200
    UNION ALL sel ect 'Номенклатура2', strftime('2022-01-22T00:00:00.000'), 200
    UNION ALL sel ect 'Номенклатура2', strftime('2022-01-29T00:00:00.000'), 200
    UNION ALL sel ect 'Номенклатура3', strftime('2022-01-15T00:00:00.000'), 300
    UNION ALL sel ect 'Номенклатура3', strftime('2022-01-19T00:00:00.000'), 300
    )

    SEL ECT
    t.p
    ,MAX(iif(t.c = t.pred_c, null, t.d)) as pred_d
    fr om
    (SEL ECT
    t.p as p
    ,t.d as d
    ,t.c as c
    ,LAG(t.c) over(partition by t.p ORDER by t.d) as pred_c
    FR OM
    vt_data as t
    ) as t
    group by
    t.p

    На выходе:
    p pred_d
    ------------------------------------------------
    Номенклатура1 2022-01-23
    Номенклатура2 2022-01-19
    Номенклатура3 2022-01-15
```
---
Получилось?
---
Спасибо!!
Получилось вот так:

```1c
    ВЫБРАТЬ
    ЦеныНоменклатуры.Номенклатура,
    ЦеныНоменклатуры.Период КАК Период,
    ЦеныНоменклатуры.Цена
    ПОМЕСТИТЬ ВТ_ВсеЦены
    ИЗ
    РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
    ГДЕ
    ЦеныНоменклатуры.ТипЦен = &ТипЦен
    И ЦеныНоменклатуры.Номенклатура В(&Номенклатура)
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ВТ_ВсеЦены.Номенклатура КАК Номенклатура,
    МАКСИМУМ(ВТ_ВсеЦены.Период) КАК Период
    ПОМЕСТИТЬ ВТ_ДатыПредыдущейЦены
    ИЗ
    ВТ_ВсеЦены КАК ВТ_ВсеЦены
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
    ПО ВТ_ВсеЦены.Номенклатура = ЦеныНоменклатуры.Номенклатура
    И ВТ_ВсеЦены.Цена <> ЦеныНоменклатуры.Цена
    И ВТ_ВсеЦены.Период < ЦеныНоменклатуры.Период
    ГДЕ
    ЦеныНоменклатуры.ТипЦен = &ТипЦен
    И ЦеныНоменклатуры.Номенклатура В(&Номенклатура)

    СГРУППИРОВАТЬ ПО
    ВТ_ВсеЦены.Номенклатура
    ;

    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ВТ_ВсеЦены.Номенклатура,
    МИНИМУМ(ВТ_ВсеЦены.Период) КАК Период
    ИЗ
    ВТ_ВсеЦены КАК ВТ_ВсеЦены
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ДатыПредыдущейЦены КАК ВТ_ДатыПредыдущейЦены
    ПО ВТ_ВсеЦены.Номенклатура = ВТ_ДатыПредыдущейЦены.Номенклатура
    И ВТ_ВсеЦены.Период > ВТ_ДатыПредыдущейЦены.Период

    СГРУППИРОВАТЬ ПО
    ВТ_ВсеЦены.Номенклатура
```
---
Кто 1С мешает отказаться от файловой базы и использовать PsgSQL? Маркетологи?

Опять же в файловой рисуют программисты 1С. Кто им мешает сделать единообразно как в СУБД?
Кто им мешает внутри использовать тот же SQLite, а не изобретать свой велосипед?
В 1С++ 77 файловые давно такая возможность есть и именно через SQLite - более 10-ти лет точно.

Ответ: никто не мешает.

Поэтому и пишу - откуда они это придумали - не знаю. Это их личная инициатива придумать себе палки в колеса.