powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Как посчитать длительность периодов в диапазоне?
25 сообщений из 25, страница 1 из 1
Как посчитать длительность периодов в диапазоне?
    #39317915
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть список услуг.
У услуг есть абонентская плата и характеристика периодичности услуги/абонплаты: ежесуточная, ежемесячная, ежегодная. Период может быть фиксированным (по границам месяца или года) или плавающим (по 20 числам месяца), кроме того он может быть кратным (каждые 5 дней, каждые 2 месяца).
Например:
УслугаАбонплатаПериодУслуга110ЕжедневноУслуга220Каждые 3 дняУслуга3200Каждый месяц (1-го числа)Услуга430010-го числа каждого месяцаУслуга5200020 февраля каждого года
У услуги также есть статус (включена/выключена), он может изменяться в произвольные моменты времени (без привязки к периодичности услуги).
Например:
УслугаСтатусНачалоКонецУслуга1Включена2016-01-012016-02-01Услуга1Выключена2016-02-012016-02-20Услуга1Включена2016-02-20-Услуга2Включена2016-05-042016-05-20Услуга2Выключена2016-05-20-Услуга3Включена2016-02-012016-06-07Услуга3Выключена2016-06-07-Услуга4Включена2016-03-05-Услуга5Включена2016-03-022017-02-20
Задан период с Дата1 по Дата2 и мне нужно посчитать, какое количество дней в этом периоде услуга была включена, а также просуммировать долю абонплаты за этот период (другими словами — вычислить абонплату за сутки и просуммировать ее за периоды, пока услуга была включена).

Я это делал следующим образом — разгруппировывал периоды (например период с 2016-02-01 по 2016-02-20 превращался в 20 дней с соответствующими датами), отбирал из этих дат период с Дата1 по Дата2, фильтровал по включенному статусу, а затем снова группировал, суммируя строки (дни) и суммы.
Но это довольно накладно для сервера, запрос выполняется долго.
Можно ли оптимизировать запрос таким образом, чтобы не "разворачивать" периоды в дни, а сразу отобрать только те периоды, когда услуга была включена, "обрезав" интервалы так, чтобы они не выходили за пределы Дата1-Дата2?
________________________
Мы смотрим с оптимизмом...
...в оптический прицел.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39317954
Alibek B.,

Скока нонче платят в биллинговом бизнесе?
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39317979
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А тупо просуммировать не вариант?
Код: plsql
1.
2.
3.
4.
5.
6.
select "Услуга", sum(least(nvl("Конец",:period_END), :period_END) - greatest("Начало", :period_START) +1) "Влючено, дней"
from "таблица статусов"
where "Статус" = 'Включена'
   and "Начало" <= :period_END
   and "Конец" >= :period_START
group by "Услуга"
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39317981
д0k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39317992
д0k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alibek B.
Можно ли оптимизировать запрос таким образом, чтобы не "разворачивать" периоды в дни, а сразу отобрать только те периоды, когда услуга была включена, "обрезав" интервалы так, чтобы они не выходили за пределы Дата1-Дата2?


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



автор________________________
Мы смотрим с оптимизмом...
...в оптический прицел.

Будь я модератором , я бы тебя забанил за такую подписть , за ксенофобию .
тут тебе не ПТ.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318049
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousА тупо просуммировать не вариант?
Проверю, может быть и подойдет.
Я когда уже опубликовал сообщение, тоже про такое подумал.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318059
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
д0kНаоборот надо делать
переводить период в интервал

Наоборот сделать нельзя, понятие интервала в Oracle не совпадает с понятием интервала в БС.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318062
д0k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alibek B.д0kНаоборот надо делать
переводить период в интервал

Наоборот сделать нельзя, понятие интервала в Oracle не совпадает с понятием интервала в БС.


Это конечно не мое дело , но если факты в БД , такие как как интервал использвания
услуги с точки зрения клиента отличается от интервала в бизнес логике ПО ,
то компании используеющей такое ПО на открытом рынке не долго жить ...
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318108
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
д0kто компании используеющей такое ПО на открытом рынке не долго жить ...
Не хотелось бы разрушать стройную картину мира.
Но мир сложнее, чем некоторые думают.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318613
stax..
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.,

1) выбрасываем выключенные услуги
2) пересечения интервала услуги и диапазона расчета
3) для каждого типа услуги вычисляем число "срабатываний" (напр раз в неделю достаточно расплывчитое условие)
4) умножаем к-во на абонплату


п.3 обычно обростает массой нюансов, напр 60-дней ето 2 месяца или все-таки меньше
.....
stax
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318868
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stax..3) для каждого типа услуги вычисляем число "срабатываний" (напр раз в неделю достаточно расплывчитое условие)
4) умножаем к-во на абонплату
Не понял про третий пункт.
Что такое "число срабатываний"?
Если доля времени работы услуги к ее общей длительности (например для услуги с месячной абонплатой если услуга была включена 15 дней, это будет 15/30), то там все довольно непросто, но у меня уже есть алгоритм, который дает те же результаты, что программный код БС.
Были затруднения, как посчитать эту длительность просто в днях, но andrey_anonymous подсказал и вроде бы получается правильно.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318879
stax..
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.stax..3) для каждого типа услуги вычисляем число "срабатываний" (напр раз в неделю достаточно расплывчитое условие)
4) умножаем к-во на абонплату
Не понял про третий пункт.
Что такое "число срабатываний"?
Если доля времени работы услуги к ее общей длительности (например для услуги с месячной абонплатой если услуга была включена 15 дней, это будет 15/30), то там все довольно непросто, но у меня уже есть алгоритм, который дает те же результаты, что программный код БС.
Были затруднения, как посчитать эту длительность просто в днях, но andrey_anonymous подсказал и вроде бы получается правильно.
не знаю Вашего задания, напр
Каждый месяц (1-го числа)
период услуги 02-09-16 по 30-09-16 надо платить или нет

Каждые 3 дня - виходные/праздничные учитывать или нет
каждые 2 месяца - тож проблема что считать "полным" месяцем

и тд

.....
stax
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318886
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.Не понял про третий пункт.
Что такое "число срабатываний"?


Hу нашел ты пересечения заданного периода (я бы не использовал терм интервал а то уже пошли ассоциации с типом данных) с периoдами включенной услуги. Но потом же тебе придется подсчитать сколько раз услуга попaдает в эти пересчения. Hапример для Услуга3 подсчитать сколько раз 1-го числo месяца попaдает в эти пересчения. Это и есть "число срабатываний".
Кстати, формула "каждые 3 дня" недетерминирована. Нет точки отсчeта.

SY.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318890
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYКстати, формула "каждые 3 дня" недетерминирована. Нет точки отсчeта.


Хотя возможно и нет, если точкa отсчeта начало периода.

SY.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318956
stax..
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYAlibek B.Не понял про третий пункт.
Что такое "число срабатываний"?


Hу нашел ты пересечения заданного периода (я бы не использовал терм интервал а то уже пошли ассоциации с типом данных) с периoдами включенной услуги. Но потом же тебе придется подсчитать сколько раз услуга попaдает в эти пересчения. Hапример для Услуга3 подсчитать сколько раз 1-го числo месяца попaдает в эти пересчения. Это и есть "число срабатываний".
Кстати, формула "каждые 3 дня" недетерминирована. Нет точки отсчeта.

SY.
пересечение важно
но дальше проблемы, имхо, луче оформить в ф-цию
напр понятие каждые 2 месяца очень расплывчато, я через ето прошел
даже месяц и то сложно

напр депозит на месяц, в рекламках есть, по факту у нас в днях

.....
stax
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318972
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С подсчетом дней все получилось, спасибо за советы.

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

Не подскажите, можно ли тут все же обойтись без временных таблиц?
В крайнем случае устроит VIEW (обычный или материализованный), но хотелось бы обойтись без него.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39318976
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.А тариф на услуге может изменяться, и дата смены тарифа никак не связана со статусом услуги (а в общем случае она не привязана и к периодичности тарифа, т.е. тариф можно изменять досрочно).
Поясню.
Например в исходном примере у Услуги4 у статуса вообще один период (услуга как включилась, так более и не изменялась), а тариф в этом периоде мог меняться несколько раз.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319014
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И в чем проблема?

1. Hаходишь пересечения заданного периода с периoдами включенной услуги.
2. Hаходишь пересечения полученных периодoв с периoдами тарифа
3. Hаходишь "число срабатываний" в каждом периоде и умножаешь на тариф данного периодa.

SY.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319028
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
3. Период, в котором услуга "срабатывает" и период в котором действует тариф — это совершенно разные периоды.
По отдельности каждый из них я могу определить.
А затем мне нужно перенести эти разные периоды в один совмещенный.
Графически это выглядит так:
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319052
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну так я и сказал - поэтапно. Например задан период:

1/1/2015 - 12/31/2015.

Услуга 1 включена:

7/12/2014 - 3/25/2015
5/11/2015 - 7/18/2015
10/10/2015 - 2/28/2016

Тарифы:

7/12/2014 - 1/25/2015 1р
1/26/2015 - 5/15/2015 2p
5/16/2015 - 9/27/2015 3p
9/28/2015 - 2/19/2016 4p

Делаем пересeчение заданного периодa и услуга 1 включена. Получаем:

1/1/2015 - 3/25/2015
5/11/2015 - 7/18/2015
10/10/2015 - 12/31/2015

Теперь пересeчение полученных периодов с периoдами таpифа:

1/1/2015 - 1/25/2015 1р
5/11/2015 - 5/15/2015 2p
5/16/2015 - 7/18/2015 3p
10/10/2015 - 12/31/2015 4p

Посколько услуга 1 имеет периодичность "Ежедневно", имеем:

(1/25/2015 - 1/1/2015 + 1) * 1р +
(5/15/2015 - 5/11/2015 + 1) * 2p +
(7/18/2015 - 5/16/2015 + 1) * 3p
(12/31/2015 - 10/10/2015 + 1) * 4p

SY.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319157
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за пошаговое объяснение, понял идею.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319598
д0k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alibek B.3. Период, в котором услуга "срабатывает" и период в котором действует тариф — это совершенно разные периоды.
По отдельности каждый из них я могу определить.
А затем мне нужно перенести эти разные периоды в один совмещенный.
Графически это выглядит так:

Это решатется на уровне реляционной модели представления
данных( нормализация отношений).

Услуга услугой, а тариф тарифом, это разные сущьности.

При изменении тарифа на лету ставится отметка в фактах
об изменинии тарифа, но не выключается услуга.

Представление данных в БД меняется ,
но картина мира 19725331 какой была, такой и осталась
позрачной и понятной и безнес аналитику и обывателю, который пользуется услугой.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319628
д0k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alibek B.То есть у меня есть периодическая таблица со статусом услуги (включена/выключена) и еще одна периодическая таблица с тарифом услуги.
У меня пока нет предположений, как эти две несвязанных периодических таблицы "спроецировать" в один запрос. Поэтому я думаю одним запросом выгрузить во временную вспомогательную таблицу с периодами тарифов и величиной абонплаты (таблицу с полями Услуга, АбонплатаЗаСутки, Начало, Конец), а затем вторым запросом посчитать количество дней в периоде, когда услуги были включены, и связать их с первой вспомогательной таблицей для подсчета суммы абонплаты.

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

мне видится left outer join c коррелированным подзапросом.
если у вас есть смена тарифа без выключения-включения услуги,
то коррелированный подзапрос должен вам вернуть в выборке строки о факте
перехода на новый тариф,
на основании которого, вы разделите интервал предоставления услуги на несколько
интервалов.
Смотрите внимательно на планы, индексы и статистику ,
left outer join с коррелированными подзапросами
имею свойство уходить в фулсканы.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319788
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
д0k , для начала уточню, что бизнес-логика БС реализована вовсе не в БД. БД используется исключительно как хранилище данных. Вся логика реализована программным кодом на сервере приложений и там никаких противоречий с интервалами нет.

Попробую еще раз пояснить рисунком.
Есть клиенты, у клиентов есть услуги (0, 1 или много). У услуг есть ряд атрибутов, например тариф и статус.
Иллюстрация относится к услуге.
В данном примере у услуги есть 5 диапазонов, в которых действует один из возможных статусов:
- включена: с 1 до 4, с 8 до 16, с 19 и далее
- выключена: с 4 до 8, с 16 до 19
Также у услуги есть 5 диапазонов, в которых действует один из тарифов:
- тариф 50: с 1 до 6
- тариф 20: с 6 до 10
- тариф 90: с 10 до 14
- тариф 70: с 14 до 20
- тариф 50: с 20 и далее

Мне нужно за определенный период (например с 1 по 25) определить стоимость услуги.

SY натолкнул меня на мысль и я делаю следующее:
1. Получаю список диапазонов тарифов за указанный период. Это 5 диапазонов: [1-6), [6-10), [10-14), [14-20), [20-26).
2. Получаю список диапазонов включенных статусов за указанный период. Это 3 диапазона: [1-4), [8-16), [19-26).
3. Затем выполняю операцию (логическую) INTERSECT между этими диапазонами и получаю следующие 6 диапазонов: [1-4), [8-10), [10-14), [14-16), [19-20), [20-26).

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

У меня получился такой запрос:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
with
  r1 as 
  (
    select 0 as pb, 0 as pe from dual where 0=1
    union all select 1, 4 from dual
    union all select 8, 16 from dual
    union all select 19, 26 from dual
  )
, r2 as 
  (
    select 0 as pb, 0 as pe from dual where 0=1
    union all select 1, 6 from dual
    union all select 6, 10 from dual
    union all select 10, 14 from dual
    union all select 14, 20 from dual
    union all select 20, 26 from dual
  )
select '['||r1.pb||'-'||r1.pe||')' as R1, '['||r2.pb||'-'||r2.pe||')' as R2
, '['
  ||greatest(r2.pb,r1.pb)
  ||'-'
  ||least(r2.pe,r1.pe)
  ||')' as RES
from r1
join r2 on (r1.pb <= r2.pe and r2.pb <= r1.pe)


Мне кажется, что это не лучший вариант и такой результат можно получить с помощью MINUS или INTERSECT.
...
Рейтинг: 0 / 0
Как посчитать длительность периодов в диапазоне?
    #39319832
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Начни с потенциальных дат предоставления услуги:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
WITH потенциальныe_даты_услуг_в_заданном_периодe AS (...)
SELECT  SUM(t.тариф)
  FROM  потенциальныe_даты_услуг_в_заданном_периодe d,
        услугa u,
        тариф t
  WHERE u.услугa = d.услугa
    AND d.датa >= u.начало
    AND d.датa <  u.конец
    AND u.cтатус = 'Включена'
    AND t.услугa = u.услугa
    AND d.датa >= t.начало
    AND d.датa <  t.конец
/



SY.
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Как посчитать длительность периодов в диапазоне?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]