Запрос, установить дату когда цена впервые непрерывно была установлена равной текущей

1. TokarevV 30 27.03.23 09:44 Сейчас в теме
Добрый день!
УТ 10.3.8.9 сильно изменённая, платформа 8.3.16.1063
В механизме печати ценников имеется процедура, добавляющая в таблицу товаров дату, когда была установлена цена номенклатуры.
Процедура УстановитьДатыУстановокЦен(ТаблицаТоваров)
	
	ТабТо = ТаблицаТоваров.Скопировать(,"Номенклатура");
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ЦеныНоменклатурыСрезПоследних.Номенклатура,
	|	ЦеныНоменклатурыСрезПоследних.Период
	|ИЗ
	|	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
	|			,
	|			ТипЦен = &ТипЦен
	|				И Номенклатура В (&Номенклатура)) КАК ЦеныНоменклатурыСрезПоследних";
	
	Запрос.УстановитьПараметр("Номенклатура", ТабТо);
	Запрос.УстановитьПараметр("ТипЦен", ТипЦены);
	
	ТЗДатыЦен = Запрос.Выполнить().Выгрузить();
КонецПроцедуры	
Показать

Часто, документ устанавливает цену, равную установленной ранее цене (равную действующей цене). В этом случае, ценник на печать не выводится. Однако, затем среди кассиров происходят разборки, для установления и поругания того, кто не распечатал ценник. В ценнике же печатается дата последней установки цены номенклатуры, а не дата когда цена впервые (без прерывания) была установлена равной текущей.
Прошу помочь составить запрос для получения требуемой даты.
Единственное, что пока сделал
ВЫБРАТЬ
	ЦеныНоменклатурыСрезПервых.Номенклатура,
	ЦеныНоменклатурыСрезПервых.Период,
	ЦеныНоменклатурыСрезПервых.Цена
ИЗ
	РегистрСведений.ЦеныНоменклатуры.СрезПервых(
			,
			ТипЦен = &ТипЦен
				И Номенклатура В (&Номенклатура)
				И Цена В
					(ВЫБРАТЬ
						ЦеныНоменклатурыСрезПоследних.Цена
					ИЗ
						РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ТипЦен = &ТипЦен
							И Номенклатура В (&Номенклатура)) КАК ЦеныНоменклатурыСрезПоследних)) КАК ЦеныНоменклатурыСрезПервых
Показать

Однако , этот код показывает цену, которая была задолго до нужной даты (цена менялась после этого, и снова стала равной выведенной дате). И в таблице значений (используется в качестве параметра) будет множество дат, весьма вероятно, то цены перепутаются между разной номенклатуры. Не хочется делать запрос в цикле, или обращаться к основной таблице регистра сведений.
Прикрепленные файлы:
Вознаграждение за ответ
Показать полностью
Найденные решения
2. laperuz 46 27.03.23 09:51 Сейчас в теме +0.02 $m
1. Выбираем максимальный период по номенклатуре, когда цена не равна цене среза последних.
2. Выбираем минимальный период, который больше максимального из п.1
user1278383; +1 Ответить
19. Said-We 27.03.23 13:06 Сейчас в теме +0.03 $m
(18) Предыдущее значение и дату в 1С найти просто, но от этого конечно воротит :-)

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

Далее я так понимаю всё понятно.
TokarevV; +1 Ответить
20. soft_wind 27.03.23 13:25 Сейчас в теме +0.05 $m
(18) у меня такой запрос получился
выбрать //первые 1000
Таб.Номенклатура,
таб.Цена,
таб.Период
Поместить Пром
из
регистрСведений.ЦеныНоменклатуры.СрезПоследних(,ВидЦены = &ВидЦены) таб
//где
//Таб.ВидЦены = &ВидЦены
//и Год(таб.Период) = 2022
//упорядочить по
//Таб.Номенклатура
;
выбрать 
пром.Номенклатура,
Максимум(таб.Период) как Период
Поместить ПромМакс
из пром
левое соединение регистрСведений.ЦеныНоменклатуры таб
по Таб.ВидЦены = &ВидЦены
и Таб.Номенклатура = Пром.Номенклатура
и Таб.Цена <> Пром.Цена
и Таб.Период < Пром.Период
где 
таб.Период есть не null
сгруппировать по
пром.Номенклатура
;

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

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

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

упорядочить по
пром.Номенклатура

Показать
TokarevV; +1 Ответить
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. nomad_irk 72 27.03.23 09:54 Сейчас в теме
(1)
В ценнике же печатается дата последней установки цены номенклатуры, а не дата когда цена впервые (без прерывания) была установлена равной текущей.


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

Вы хотите получить дату предыдущей установленной цены?
4. TokarevV 30 27.03.23 10:01 Сейчас в теме
(3) Условие номенклатура и тип цен, СрезПоследних всегда даёт последнюю цену, требуемого типа.
5. nomad_irk 72 27.03.23 10:05 Сейчас в теме
(4)так, а вам нужна дата установки предыдущей цены?

Какой скрытый смысл устанавливать одинаковую цену разными датами?
6. laperuz 46 27.03.23 10:13 Сейчас в теме
(5)ТСу нужна дата, когда текущую цену установили. Типа 1 марта поставили 500 рублей, потом 2 и 3 марта тоже поставили цену 500 рублей. Нужно получить дату 1 марта.
(1) Я могу ошибаться конечно, но в типовых вроде в таком случае вообще движение по регистрам цен не делается, если цена не поменялась, и задача автоматически решается. Может вам тоже в эту сторону посмотреть вместо того, чтобы извращаться с запросами?
succub1_5; +1 Ответить
7. nomad_irk 72 27.03.23 10:21 Сейчас в теме
(6)Ждем ответа ТС, по какой причине устанавливаются одинаковые цены разными датами.
13. TokarevV 30 27.03.23 11:21 Сейчас в теме
(7)
Так исторически сложилось.
Как сказал 1с-ник, который работал до меня, он спросил у 1с-ник, который работал за 2 человека до него: "а почему в конфигурации всё вот так вот?". Пращур сказал, что так было уже до него.
2. laperuz 46 27.03.23 09:51 Сейчас в теме +0.02 $m
1. Выбираем максимальный период по номенклатуре, когда цена не равна цене среза последних.
2. Выбираем минимальный период, который больше максимального из п.1
user1278383; +1 Ответить
12. TokarevV 30 27.03.23 11:18 Сейчас в теме
(2) Придётся обращаться к основной таблице регистра?
14. laperuz 46 27.03.23 11:21 Сейчас в теме
8. soft_wind 27.03.23 10:24 Сейчас в теме
еще как вариант подправить Установку цен, что бы этот документ не писал цену в регистр если она не изменялась!
(место за одно сэкономите)
9. nomad_irk 72 27.03.23 10:37 Сейчас в теме
(8)вангую, там какая-то обработка загружает/устанавливает цены, несмотря на их историю.
11. user1863362 27.03.23 10:49 Сейчас в теме
(8)
если она не изменялась
Бессмыслено. Таже самая ситуация будет возникать в других случаях:

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

Удаляем Док2 и все. Ну и вообще при работе задним/будущим числом все поплывет.
10. soft_wind 27.03.23 10:44 Сейчас в теме
(9) на сам регистр, в событие ПередЗаписью, добавил условие проверки/отсеивания всего того что не изменилось!
15. Said-We 27.03.23 11:44 Сейчас в теме
(1) В чем сложность-то?
Для каждой цены равной текущей (текущая цена сама себе тоже равна) находишь предыдущую цену. Там где цена была другой тебя и интересует. Находишь среди них максимальную. Ну, собственно тебе не цена нужна, а дата установки. Усё.
16. TokarevV 30 27.03.23 11:57 Сейчас в теме
(15)
Не понял твой комментарий, напиши, пожалуйста, подробней.
17. Said-We 27.03.23 12:07 Сейчас в теме
(16) Как тут ещё подробнее. У тебя таблица из номенклатуры и цены текущей. Это фильтр. Для всех движений цены по этому фильтру находишь предыдущее значение. Предыдущее значение ищется по всем движениям без фильтра.
Как найти предыдущее значение думаю нет сложностей. В стандартном SQL это функция LAG(), в 1С это несколько джоинов.
Далее берешь только те, где цена НЕ совпадает. Среди них находишь максимальную дату. Усё.

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


У меня весь вопрос про то, как найти предыдущее значение. Период, когда текущая цена установлена впервые (без перерыва).
23. Said-We 27.03.23 19:05 Сейчас в теме
(18)
У меня весь вопрос про то, как найти предыдущее значение


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

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

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

Далее соединяете таблицу саму с собой по условию WHERE т1.номенклатура = т2.номенклатура and т1.нпп = т2.нпп+1
Собственно всё.
24. user1863362 27.03.23 19:32 Сейчас в теме
(23)
В СУБД таких ограничений нет
Ты все время, ненавязчиво так, забываешь про файловую базу. То, что она тебе лично не нужна, не делает её менее востребованной.
19. Said-We 27.03.23 13:06 Сейчас в теме +0.03 $m
(18) Предыдущее значение и дату в 1С найти просто, но от этого конечно воротит :-)

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

Далее я так понимаю всё понятно.
TokarevV; +1 Ответить
20. soft_wind 27.03.23 13:25 Сейчас в теме +0.05 $m
(18) у меня такой запрос получился
выбрать //первые 1000
Таб.Номенклатура,
таб.Цена,
таб.Период
Поместить Пром
из
регистрСведений.ЦеныНоменклатуры.СрезПоследних(,ВидЦены = &ВидЦены) таб
//где
//Таб.ВидЦены = &ВидЦены
//и Год(таб.Период) = 2022
//упорядочить по
//Таб.Номенклатура
;
выбрать 
пром.Номенклатура,
Максимум(таб.Период) как Период
Поместить ПромМакс
из пром
левое соединение регистрСведений.ЦеныНоменклатуры таб
по Таб.ВидЦены = &ВидЦены
и Таб.Номенклатура = Пром.Номенклатура
и Таб.Цена <> Пром.Цена
и Таб.Период < Пром.Период
где 
таб.Период есть не null
сгруппировать по
пром.Номенклатура
;

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

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

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

упорядочить по
пром.Номенклатура

Показать
TokarevV; +1 Ответить
26. TokarevV 30 28.03.23 08:49 Сейчас в теме
(20) Действительно, ваш запрос работает спасибо!
ВЫБРАТЬ
	таб.Номенклатура,
	таб.Цена,
	таб.Период
ПОМЕСТИТЬ Пром
ИЗ
	РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
			,
			ТипЦен = &ВидЦены
				И Номенклатура В (&Номенклатура)) КАК таб
;

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

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

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

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

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

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

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
Показать
22. Said-We 27.03.23 17:57 Сейчас в теме
27. TokarevV 30 28.03.23 08:50 Сейчас в теме
(22) Спасибо!!
Получилось вот так:
ВЫБРАТЬ
	ЦеныНоменклатуры.Номенклатура,
	ЦеныНоменклатуры.Период КАК Период,
	ЦеныНоменклатуры.Цена
ПОМЕСТИТЬ ВТ_ВсеЦены
ИЗ
	РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ
	ЦеныНоменклатуры.ТипЦен = &ТипЦен
	И ЦеныНоменклатуры.Номенклатура В(&Номенклатура)
;

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

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

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

СГРУППИРОВАТЬ ПО
	ВТ_ВсеЦены.Номенклатура
Показать
25. Said-We 27.03.23 19:48 Сейчас в теме
(24) Кто 1С мешает отказаться от файловой базы и использовать PsgSQL? Маркетологи?

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

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

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

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот