Многократное изменение значения в периоде (запрос)

24.10.23

Разработка - Запросы

При решении задач расчетов, а также и в других разделах учета (оперативный, бухгалтерский) встречается проблема многократного изменения значения в периоде. Рассмотрим простую задачу: Все сотрудники предприятия работают по пятидневному графику работы, совместительство не допускается. Сотрудники предприятия получают оплату по окладу пропорционально отработанному времени в днях. Дневная ставка рассчитывается как начальное значение оклада, деленное на количество рабочих дней в том же периоде, что и фактически отработанные дни. В течение расчетного периода первоначальное значение оклада может быть неоднократно изменено. В информационной базе необходимо хранить историю его изменения. Расчет должен проводиться исходя из действующего на рассчитываемую дату начального значения оклада. Например, если начальное значение оклада изменилось 5 августа, то до 5 августа при расчете берется старое значение, а начиная с 5 августа – новое, и. т. д.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Многократное изменение значения в периоде (запрос):
.dt 134,25Kb
0
0 Скачать (1 SM) Купить за 1 850 руб.

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

Исходные данные:

1. Документ начисления по окладу:

 

 

Ниже данные периодического регистра сведений с периодичностью день, в котором мы храним первоначальное значение оклада:

 

 

Итоговые интервалы со значением оклада у нас будут выглядеть так:

Сотрудник Дата начала  Дата окончания  Размер
Иванов 05.09.2023  06.09.2023  250,00
Иванов 07.09.2023  10.09.2023  200,00
Иванов 11.09.2023  14.09.2023  100,00
Иванов 15.09.2023  20.09.2023  150,00
Иванов 21.09.2023  24.09.2023  400,00
Иванов 25.09.2023  26.09.2023  300,00
Иванов 27.09.2023  28.09.2023  200,00
Петров 01.09.2023  06.09.2023  1 000,00
Петров 07.09.2023  12.09.2023  2 000,00
Петров 13.09.2023  20.09.2023  3 000,00
Петров 21.09.2023  25.09.2023  4 000,00
Петров 26.09.2023  30.09.2023  5 000,00

 

Эти итоговые данные мы должны получить запросом и рассчитать зарплату по окладу для нашим сотрудников:

 

 

План запроса:

1. объединяем срез последних РС на дату регистрации и записи РС с отбором внутри нашего месяца начисления, помещаем во временную таблицу, индексируем по Сотруднику и периоду.

2. полученную временную таблицу пронумеруем по порядку, порядок должен быть Сотрудник, Период, пронумерованную таблицу поместим во временную (таким образом можно пронумеровать только временную таблицу)

3. полученную таблицу соединяем саму с собой по сотруднику и по номеру строки со сдвигом номера на единицу, тем самым получая начало и окончания интервала. Одновременно, для конца интервала отнимаем день, а те записи которые по сотруднику не сошлись - устанавливаем для них конец периода = концу месяца регистрации, помещаем во временную таблицу

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

Готово.

3,4 пункты покажутся сначала не очень понятными, но если попробовать покрутить запрос в консоле станет понятнее.

Нужно просто представить что пронумерованную таблицу регистра мы сдвигаем на строку вверх чтобы получить дату окончания, и моя мысль станет более понятной:

      Период
Сотрудник Оклад Период 29.08.2023
Иванов 200,00 29.08.2023 01.09.2023
Иванов 300,00 01.09.2023 04.09.2023
Иванов 250,00 04.09.2023 07.09.2023
Иванов 200,00 07.09.2023 11.09.2023
Иванов 100,00 11.09.2023 15.09.2023
Иванов 150,00 15.09.2023 21.09.2023
Иванов 400,00 21.09.2023 25.09.2023
Иванов 300,00 25.09.2023 27.09.2023
Иванов 200,00 27.09.2023 29.09.2023
Иванов 500,00 29.09.2023 01.08.2023
Петров 1 000,00 01.08.2023 07.09.2023
Петров 2 000,00 07.09.2023 13.09.2023
Петров 3 000,00 13.09.2023 21.09.2023
Петров 4 000,00 21.09.2023 26.09.2023
Петров 5 000,00 26.09.2023  
       
    это период начала Это период окончания - здесь сдвинули наверх на одну строку и отняли день, чтобы получить конец интервала, а если дата получилась пустая, то добавили месяц к периоду регистрации и тоже отняли день

 

Запрос будет выглядеть следующим образом:

Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    СведенияОСотрудниках.Период КАК Период,
    |    СведенияОСотрудниках.Сотрудник КАК Сотрудник,
    |    СведенияОСотрудниках.Оклад КАК Оклад
    |ПОМЕСТИТЬ ВТ
    |ИЗ
    |    РегистрСведений.СведенияОСотрудниках КАК СведенияОСотрудниках
    |ГДЕ
    |    СведенияОСотрудниках.Период МЕЖДУ &ПериодРегистрации И ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1), СЕКУНДА, -1)
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    |    &ПериодРегистрации,
    |    СведенияОСотрудникахСрезПоследних.Сотрудник,
    |    СведенияОСотрудникахСрезПоследних.Оклад
    |ИЗ
    |    РегистрСведений.СведенияОСотрудниках.СрезПоследних(&ПериодРегистрации, ) КАК СведенияОСотрудникахСрезПоследних
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    Сотрудник,
    |    Период
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
    |    ВТ.Период КАК Период,
    |    ВТ.Сотрудник КАК Сотрудник,
    |    ВТ.Оклад КАК Оклад
    |ПОМЕСТИТЬ ВТ1
    |ИЗ
    |    ВТ КАК ВТ
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    Сотрудник,
    |    Период
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    ВТ1.Период КАК НачалоПериода,
    |    ДОБАВИТЬКДАТЕ(ЕСТЬNULL(ВТ11.Период, ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1)), ДЕНЬ, -1) КАК КонецПериода,
    |    ВТ1.Сотрудник КАК Сотрудник,
    |    ВТ1.Оклад КАК Оклад
    |ПОМЕСТИТЬ ВТ2
    |ИЗ
    |    ВТ1 КАК ВТ1
    |        ЛЕВОЕ СОЕДИНЕНИЕ ВТ1 КАК ВТ11
    |        ПО (ВТ1.НомерСтроки = ВТ11.НомерСтроки - 1)
    |            И ВТ1.Сотрудник = ВТ11.Сотрудник
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    НачислениеЗарплатыОсновныеНачисления.Сотрудник КАК Сотрудник,
    |    ВЫБОР
    |        КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
    |            ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
    |        ИНАЧЕ ВТ2.НачалоПериода
    |    КОНЕЦ КАК ДатаНачала,
    |    ВЫБОР
    |        КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
    |            ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
    |        ИНАЧЕ ВТ2.КонецПериода
    |    КОНЕЦ КАК ДатаОкончания,
    |    ВТ2.Оклад КАК Размер
    |ИЗ
    |    ВТ2 КАК ВТ2
    |        ПОЛНОЕ СОЕДИНЕНИЕ Документ.НачислениеЗарплаты.ОсновныеНачисления КАК НачислениеЗарплатыОсновныеНачисления
    |        ПО ВТ2.Сотрудник = НачислениеЗарплатыОсновныеНачисления.Сотрудник
    |ГДЕ
    |    НачислениеЗарплатыОсновныеНачисления.Ссылка = &Ссылка
    |    И НачислениеЗарплатыОсновныеНачисления.ВидРасчета = &Оклад
    |    И ВЫБОР
    |            КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
    |                ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
    |            ИНАЧЕ ВТ2.НачалоПериода
    |        КОНЕЦ <= ВЫБОР
    |            КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
    |                ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
    |            ИНАЧЕ ВТ2.КонецПериода
    |        КОНЕЦ";

Тестирование проводилось на платформе 8.3.18.1289.

Запрос конфигурация значение в периоде расчет

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

12000 руб.

02.09.2020    168183    929    403    

900

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    11251    sergey279    18    

65

Запросы Программист Платформа 1С v8.3 Запросы Конфигурации 1cv8 Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    6217    XilDen    36    

83

Запросы Программист Запросы Бесплатно (free)

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

16.08.2024    8939    user1840182    5    

28

Математика и алгоритмы Запросы Программист Платформа 1С v8.3 Запросы Бесплатно (free)

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

08.07.2024    2695    ivanov660    9    

22

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

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

15.05.2024    10076    implecs_team    6    

48

Запросы Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Часто поступают задачи по произвольному распределению общих сумм. После распределения иногда пропадают копейки. Суть решения добавить АвтоНомерЗаписи() в ВТ распределения, и далее используя функции МАКСИМУМ или МИНИМУМ можем положить разницу копеек в первую или последнюю строку знаменателя распределения.

11.04.2024    3602    andrey_sag    10    

38
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. tormozit 7242 24.10.23 10:29 Сейчас в теме
Чтобы гарантировать правильтный порядок "АВТОНОМЕРЗАПИСИ() КАК НомерСтроки", нужно добавить ПЕРВЫЕ 10000000 и УПОРЯДОЧИТЬ. https://github.com/SeiOkami/OneS/issues/268
2. malinapc 25.10.23 10:46 Сейчас в теме
(1)
Комментарии

Нам главное получить номера строк без дублей, чтобы связать таблицу саму с собой по номерстроки = номерстроки-1, так что это видимо не проблема
3. Gesperid 2 01.11.23 12:00 Сейчас в теме
Во-первых
ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1), СЕКУНДА, -1)
можно заменить на
КОНЕЦПЕРИОДА(&ПериодРегистрации, МЕСЯЦ)

Во-вторых получить интервалы по списку дат можно без нумерации.
ВЫБРАТЬ
	ДатыС.Измерения КАК Измерения,
	ДатыС.ДополнительныеПоля КАК ДополнительныеПоля,
	ДатыС.ИмяПоляДата КАК ДатаС,
	ЕСТЬNULL(МИНИМУМ(ДатыДо.ИмяПоляДата), ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59)) КАК ДатаДо
ПОМЕСТИТЬ ВТИнтервалы
ИЗ
	втДаты КАК ДатыС
		ЛЕВОЕ СОЕДИНЕНИЕ втДаты КАК ДатыДо
		ПО ДатыС.Измерения = ДатыДо.Измерения
			И ДатыС.ИмяПоляДата < ДатыДо.ИмяПоляДата

СГРУППИРОВАТЬ ПО
	ДатыС.ИмяПоляДата,
	ДатыС.ДополнительныеПоля,
	ДатыС.Измерения
Показать

см. https://its.1c.ru/db/metod81#content:2910:hdoc, типовые и публикации на ИС.
4. malinapc 14.11.23 23:08 Сейчас в теме
1. Совершенно согласен, так будет лучше.

2. Я хотел показать как эту задачу можно решить с помощью функции АВТОНОМЕРЗАПИСИ() пронумеровав строки временной таблицы, конечно же, как справедливо было замечено, можно обойтись без нее, запрос в этом случае будет выглядеть следующим образом

Вариант запроса №2:

ВЫБРАТЬ РАЗЛИЧНЫЕ
СведенияОСотрудниках.Период КАК Период,
СведенияОСотрудниках.Сотрудник КАК Сотрудник,
СведенияОСотрудниках.Оклад КАК Оклад
ПОМЕСТИТЬ ВТ
ИЗ
РегистрСведений.СведенияОСотрудниках КАК СведенияОСотрудниках
ГДЕ
СведенияОСотрудниках.Период МЕЖДУ &ПериодРегистрации И КОНЕЦПЕРИОДА(&ПериодРегистрации, МЕСЯЦ)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
&ПериодРегистрации,
СведенияОСотрудникахСрезПоследних.Сотрудник,
СведенияОСотрудникахСрезПоследних.Оклад
ИЗ
РегистрСведений.СведенияОСотрудниках.СрезПоследних(&ПериодРегистрации, ) КАК СведенияОСотрудникахСрезПоследних

ИНДЕКСИРОВАТЬ ПО
Сотрудник,
Период
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
ВТНачало.Период КАК НачалоПериода,
МИНИМУМ(ДОБАВИТЬКДАТЕ(ЕСТЬNULL(ВТКонец.Период, ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1)), ДЕНЬ, -1)) КАК КонецПериода,
ВТНачало.Сотрудник КАК Сотрудник,
ВТНачало.Оклад КАК Оклад
ПОМЕСТИТЬ ВТ2
ИЗ
ВТ КАК ВТНачало
ЛЕВОЕ СОЕДИНЕНИЕ ВТ КАК ВТКонец
ПО ВТНачало.Сотрудник = ВТКонец.Сотрудник
И ВТНачало.Период < ВТКонец.Период

СГРУППИРОВАТЬ ПО
ВТНачало.Период,
ВТНачало.Сотрудник,
ВТНачало.Оклад

ИНДЕКСИРОВАТЬ ПО
Сотрудник,
НачалоПериода
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
НачислениеЗарплатыОсновныеНачисления.Сотрудник КАК Сотрудник,
ВЫБОР
КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
ИНАЧЕ ВТ2.НачалоПериода
КОНЕЦ КАК ДатаНачала,
ВЫБОР
КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
ИНАЧЕ ВТ2.КонецПериода
КОНЕЦ КАК ДатаОкончания,
ВТ2.Оклад КАК Размер
ИЗ
ВТ2 КАК ВТ2
ПОЛНОЕ СОЕДИНЕНИЕ Документ.НачислениеЗарплаты.ОсновныеНачисления КАК НачислениеЗарплатыОсновныеНачисления
ПО ВТ2.Сотрудник = НачислениеЗарплатыОсновныеНачисления.Сотрудник
ГДЕ
НачислениеЗарплатыОсновныеНачисления.Ссылка = &Ссылка
И НачислениеЗарплатыОсновныеНачисления.ВидРасчета = &Оклад
И ВЫБОР
КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
ИНАЧЕ ВТ2.НачалоПериода
КОНЕЦ <= ВЫБОР
КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
ИНАЧЕ ВТ2.КонецПериода
КОНЕЦ
5. user1960156 27.07.24 09:52 Сейчас в теме
А зачем использовать "выбрать различные" 1ом, 3ем и 4ом запросе? И такой вопрос: почему в последнем запросе используется "полное соединение"?
6. user1960156 27.07.24 10:22 Сейчас в теме
(5) И разве не должно быть соединение по НомерСтроки+1? КонецПериода же это следующая строка, а не предыдущая?
7. user1960156 27.07.24 11:53 Сейчас в теме
(6) а нет, виноват, -1 верно
Оставьте свое сообщение