Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Задача с пересекающимися диапазонами / 25 сообщений из 40, страница 1 из 2
21.07.2010, 10:02
    #36751713
Буремиг
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Здравствуйте,

Есть таблица с двумя столбцами дата_начала, дата_конца. Задача выяснить максимальное количество строк диапазоны которых дата_начала и дата_конца пересекаются. Например это может быть звонковая таблица с началом и окончанием звонка, тогда задача формулируется: выяснить максимально количество звонков, которые были одновременно (пиковая нагрузка). В таблице находятся звонки совершенные за сутки.

У меня есть пока две идеи как можно решить такую задачу.
1-ый Вариант: берем каждую строку таблицы и по дате начала из этой строки соединяем табличку саму на себя и считаем сколько звонков было одновременно с этой строчкой. Далее выбираем максимальное количество звонков.

2-ой Вариант: Поскольку звонки в таблице только за сутки. Разбиваем сутки на N точек времени и в каждую точку времени считаем количество звонков. Потом выбираем максимальное количество. Естественно это вариант теряет в точности т.к. некоторые звонки могут потерятся и не будут учтены.

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

Подскажите, пожалуйста, может есть какое еще оптимальное решение данной задачи?

Спасибо.
...
Рейтинг: 0 / 0
21.07.2010, 10:12
    #36751730
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Буремигзадача формулируется: выяснить максимально количество звонков, которые были одновременно (пиковая нагрузка).
Что должно получиться на таких данных?

дата_началадата_конца00:01:0000:02:0100:02:0000:03:0100:03:0000:04:0100:04:0000:05:01 ......23:57:0023:58:0123:58:0023:59:01
...
Рейтинг: 0 / 0
21.07.2010, 10:35
    #36751766
-2-
-2-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Буремиг,

count(звонок) over(order by время range between current row and interval 'одновременно' minute|/second following)
...
Рейтинг: 0 / 0
21.07.2010, 10:52
    #36751807
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
БуремигПодскажите, пожалуйста, может есть какое еще оптимальное решение данной задачи?
1. Количество одновременных звонков меняется в момент начала очередного звонка (увеличивается) и завершения (уменьшается). Максимальное количество достигается в момент увеличения. Таким образом, имеет смысл считать количество звонков только на date_start каждого звонка.

2. Количество одновременных звонков = номер_звонка_по_порядку - количество_успевших_завершиться.

Отсюда вывод: строится выборка вида (дата_начала; кол-во успевших завершиться с предыдущей даты начала) и в общем уже всё просто.

3. Если задача учебная, то, думаю, хватит. Если же боевая - подозреваю, что оптимальная реализация таки будет PL/SQL-ной, причём формулировка сменится с "найти точную пиковую нагрузку" на что-нибудь типа "найти интервалы времени, когда нагрузка не менее 70% от пиковой".
...
Рейтинг: 0 / 0
21.07.2010, 11:32
    #36751918
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Отправной запрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
create table tmp (b timestamp, e timestamp);

declare
  d timestamp := date '2010-07-21';
begin
  dbms_random.seed( 1 );
  for i in  1  ..  100  loop
    d := d + numtodsinterval(abs(dbms_random.normal), 'minute');
    insert into tmp values(d, d + numtodsinterval(abs(dbms_random.normal)* 2 , 'minute'));
  end loop;
  commit;
end;
/
Код: plaintext
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.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
select * from (
select
    t.time as b,
    lead(t.time)  over (order by t.time, t.weight desc) as e,
    sum(t.weight) over (order by t.time, t.weight desc) as cnt
  from
  ( select b as time, + 1  as weight from tmp
    union all
    select e as time, - 1  as weight from tmp
  ) t
) where cnt not between  1  and  4  and e is not null
;

B                              E                                        CNT
------------------------------ ------------------------------ -------------
 21 -JUL- 10   12 . 11 . 36 . 390948  AM    21 -JUL- 10   12 . 11 . 48 . 094885  AM                0 
 21 -JUL- 10   12 . 14 . 21 . 716310  AM    21 -JUL- 10   12 . 14 . 29 . 557452  AM                5 
 21 -JUL- 10   12 . 22 . 46 . 133088  AM    21 -JUL- 10   12 . 22 . 58 . 283495  AM                0 
 21 -JUL- 10   12 . 24 . 18 . 229331  AM    21 -JUL- 10   12 . 24 . 31 . 754259  AM                0 
 21 -JUL- 10   12 . 28 . 27 . 101885  AM    21 -JUL- 10   12 . 28 . 27 . 873431  AM                5 
 21 -JUL- 10   12 . 28 . 27 . 873431  AM    21 -JUL- 10   12 . 28 . 42 . 108058  AM                6 
 21 -JUL- 10   12 . 28 . 42 . 108058  AM    21 -JUL- 10   12 . 28 . 46 . 661074  AM                5 
 21 -JUL- 10   12 . 32 . 39 . 169498  AM    21 -JUL- 10   12 . 32 . 48 . 645544  AM                0 
 21 -JUL- 10   12 . 34 . 53 . 449429  AM    21 -JUL- 10   12 . 35 . 18 . 936116  AM                0 
 21 -JUL- 10   12 . 42 . 08 . 488375  AM    21 -JUL- 10   12 . 42 . 28 . 383927  AM                0 
 21 -JUL- 10   12 . 45 . 51 . 769852  AM    21 -JUL- 10   12 . 45 . 55 . 840668  AM                5 
 21 -JUL- 10   12 . 46 . 20 . 081502  AM    21 -JUL- 10   12 . 46 . 20 . 161565  AM                5 
 21 -JUL- 10   12 . 46 . 39 . 977951  AM    21 -JUL- 10   12 . 46 . 50 . 730661  AM                5 
 21 -JUL- 10   12 . 46 . 53 . 648698  AM    21 -JUL- 10   12 . 47 . 00 . 518197  AM                5 
 21 -JUL- 10   12 . 47 . 00 . 518197  AM    21 -JUL- 10   12 . 47 . 17 . 835443  AM                6 
 21 -JUL- 10   12 . 47 . 17 . 835443  AM    21 -JUL- 10   12 . 47 . 20 . 130730  AM                5 
 21 -JUL- 10   12 . 47 . 27 . 512701  AM    21 -JUL- 10   12 . 47 . 35 . 731410  AM                5 
 21 -JUL- 10   12 . 48 . 43 . 793233  AM    21 -JUL- 10   12 . 48 . 46 . 033367  AM                0 
 21 -JUL- 10   12 . 50 . 50 . 062366  AM    21 -JUL- 10   12 . 50 . 53 . 328105  AM                5 
 21 -JUL- 10   12 . 50 . 53 . 328105  AM    21 -JUL- 10   12 . 51 . 00 . 417536  AM                6 
 21 -JUL- 10   12 . 51 . 00 . 417536  AM    21 -JUL- 10   12 . 51 . 08 . 336471  AM                5 
 21 -JUL- 10   12 . 52 . 02 . 805583  AM    21 -JUL- 10   12 . 52 . 02 . 823889  AM                5 
 21 -JUL- 10   12 . 54 . 03 . 039562  AM    21 -JUL- 10   12 . 54 . 03 . 597516  AM                0 
 21 -JUL- 10   12 . 54 . 14 . 639595  AM    21 -JUL- 10   12 . 54 . 40 . 243264  AM                0 
 21 -JUL- 10   12 . 55 . 51 . 129239  AM    21 -JUL- 10   12 . 56 . 09 . 142492  AM                0 
 21 -JUL- 10   01 . 04 . 13 . 344180  AM    21 -JUL- 10   01 . 04 . 43 . 378769  AM                5 

 26  rows selected.
Дальше его можно соединять с эталонными интервалами, выбирать максимум, ...

P.S. PL/SQL тут отдыхает :)
...
Рейтинг: 0 / 0
21.07.2010, 11:38
    #36751942
SQL*Plus
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
softwarer1. Количество одновременных звонков меняется в момент начала очередного звонка (увеличивается) и завершения (уменьшается). Оно уменьшается "в момент, следующий за завершением звонка".
...
Рейтинг: 0 / 0
21.07.2010, 11:41
    #36751952
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
SQL*PlusОно уменьшается "в момент, следующий за завершением звонка".
Не подскажете ли, какое именно число "следует за числом 1.28342"?
...
Рейтинг: 0 / 0
21.07.2010, 11:58
    #36752017
SQL*Plus
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
softwarerSQL*PlusОно уменьшается "в момент, следующий за завершением звонка".Не подскажете ли, какое именно число "следует за числом 1.28342"?Не подскажу... :-)
Но в звонках используются DATE. Значения этого типа данных дискретны.
"момент, следующий за завершением звонка" = "дата-время завершения звонка" + 1 секунда.
"По-моему, так!" :-)
...
Рейтинг: 0 / 0
21.07.2010, 12:22
    #36752100
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
SQL*PlusНо в звонках используются DATE. Значения этого типа данных дискретны.
Значения любого примитивного типа данных дискретны. В том числе number-а.

SQL*Plus"момент, следующий за завершением звонка" = "дата-время завершения звонка" + 1 секунда. "По-моему, так!" :-)
Даже если формат представления непрерывных данных дискретен, попытка работать с ними в этом ключе приводит только к дополнительному геморрою, имхо. Грубо говоря, из вариантов

Код: plaintext
1.
2.
 1 . trunc (dt) = trunc (sysdate)
 2 . dt >= trunc (sysdate) and dt < trunc (sysdate+ 1 )
 3 . dt >= trunc (sysdate) and dt <= trunc (sysdate+ 1 ) -  1 / 86400 

весьма трудно назвать хоть какой-либо плюс третьего. В том числе и с точки зрения бизнес-логики гораздо удобнее работать на полуоткрытых интервалах.
...
Рейтинг: 0 / 0
21.07.2010, 12:29
    #36752113
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
softwarerиз вариантов

Код: plaintext
1.
2.
 1 . trunc (dt) = trunc (sysdate)
 2 . dt >= trunc (sysdate) and dt < trunc (sysdate+ 1 )
 3 . dt >= trunc (sysdate) and dt <= trunc (sysdate+ 1 ) -  1 / 86400 

весьма трудно назвать хоть какой-либо плюс третьего.
Один плюсик таки есть: его можно переписать как
Код: plaintext
dt between trunc (sysdate) and trunc (sysdate+ 1 ) -  1 / 86400 
что временами слегка повышает читабельность.

В то же время вариант 1 в запросе сразу выдает "нуба", который вскоре придет с просьбой "ускорить запрос". Не на 100%, но на 98 - точно :)
...
Рейтинг: 0 / 0
21.07.2010, 12:30
    #36752115
SQL*Plus
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
softwarer,
Мы обсуждали когда наступает момент уменьшения кол-ва звонков.
Если это правильно и понятно определено, то способы учета данного факта - это уже дело техники.

P.S. Замечу, что для реальных расчетов секунда туда-сюда не имеет практически никакого значения.
...
Рейтинг: 0 / 0
21.07.2010, 12:32
    #36752124
andrey_anonymous
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
[quot SQL*PlusP.S. Замечу, что для реальных расчетов секунда туда-сюда не имеет практически никакого значения.[/quot]
Ну не скажите.
Имеет, причем существенное - если работаете с "версионными" объектами с заданными интервалами существования версий.
...
Рейтинг: 0 / 0
21.07.2010, 12:37
    #36752139
UScorp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Буремиг,

Как мне кажется будет работать ваш второй вариант с разбивкой на N точек времени, но делать это не через равный промежуток времени, а в моменты начала очередного звонка (соотвественно убрав дубликаты из этих точек времени), т.к. пиковая нагрузка возникает именно в начале какого-то определенного звонка (-ов).
...
Рейтинг: 0 / 0
21.07.2010, 12:38
    #36752143
Буремиг
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
softwarerБуремигПодскажите, пожалуйста, может есть какое еще оптимальное решение данной задачи?
1. Количество одновременных звонков меняется в момент начала очередного звонка (увеличивается) и завершения (уменьшается). Максимальное количество достигается в момент увеличения. Таким образом, имеет смысл считать количество звонков только на date_start каждого звонка.


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

Elic
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select * from (
select
    t.time as b,
    lead(t.time)  over (order by t.time, t.weight desc) as e,
    sum(t.weight) over (order by t.time, t.weight desc) as cnt
  from
  ( select b as time, + 1  as weight from tmp
    union all
    select e as time, - 1  as weight from tmp
  ) t
) where cnt not between  1  and  4  and e is not null
;
Дальше его можно соединять с эталонными интервалами, выбирать максимум, ...


Спасибо, за наглядную демонстрацию. Не додумался, что начало и конец звонка можно в одно поле сложить с весом.
...
Рейтинг: 0 / 0
21.07.2010, 12:39
    #36752145
SQL*Plus
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
andrey_anonymousSQL*PlusP.S. Замечу, что для реальных расчетов секунда туда-сюда не имеет практически никакого значения.Ну не скажите.
Имеет, причем существенное - если работаете с "версионными" объектами с заданными интервалами существования версий.Я не совсем точно выразился.
Имелось в виду - для реальных статистических расчетов.

При использовании "версионных" объектов для статистики крайне важно однозначное понимание "что такое сутки" всеми приложениями и их пользователями.
...
Рейтинг: 0 / 0
21.07.2010, 12:41
    #36752150
UScorp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
SQL*Plus, softwarer

Мне кажется что ваш спор насчет момента завершения звонка имел бы место быть если бы необходимо было определить максимальную пиковую нагрузку и интервал времени который он продолжался
...
Рейтинг: 0 / 0
21.07.2010, 12:41
    #36752154
Буремиг
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
UScorpБуремиг,

Как мне кажется будет работать ваш второй вариант с разбивкой на N точек времени, но делать это не через равный промежуток времени, а в моменты начала очередного звонка (соотвественно убрав дубликаты из этих точек времени), т.к. пиковая нагрузка возникает именно в начале какого-то определенного звонка (-ов).


Звонков много. Такой алгоритм тормозить будет. Elic - классную идею подал. За один проход получаем для каждого звонка, сколько звонков было еще активных. Плюс второй проход на выяснение максимума.
...
Рейтинг: 0 / 0
21.07.2010, 12:46
    #36752162
UScorp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
UScorp
SQL*Plus, softwarer

Мне кажется что ваш спор насчет момента завершения звонка имел бы место быть если бы необходимо было определить максимальную пиковую нагрузку и интервал времени который он продолжался

Хотя из
Буремиг
Есть таблица с двумя столбцами дата_начала, дата_конца. Задача выяснить максимальное количество строк диапазоны которых дата_начала и дата_конца пересекаются.


так и выходит
...
Рейтинг: 0 / 0
21.07.2010, 12:52
    #36752183
Буремиг
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
UScorpUScorp
SQL*Plus, softwarer

Хотя из
[quot Буремиг]
Есть таблица с двумя столбцами дата_начала, дата_конца. Задача выяснить максимальное количество строк диапазоны которых дата_начала и дата_конца пересекаются.


так и выходит

Задача только узнать пиковую нагрузку. Временные диапазоны пиковой нагрузки не нужны.
...
Рейтинг: 0 / 0
21.07.2010, 13:04
    #36752219
softwarer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
andrey_anonymousОдин плюсик таки есть: его можно переписать как что временами слегка повышает читабельность.
Имхо, это "временами" исчезающе мало.

andrey_anonymousВ то же время вариант 1 в запросе сразу выдает "нуба"
Поэтому приведены второй и третий :) Но первый таки куда лучше, например, в if-е.

SQL*PlusМы обсуждали когда наступает момент уменьшения кол-ва звонков
Не совсем так, имхо. "Когда наступает момент" - вопрос довольно философский, уровня хлопка одной ладонью. Мы знаем, когда пользователь нажал на кнопку, а вот "в этот момент звонок ещё есть или уже нет" - можно спорить совершенно попусту неограниченное количество времени; не думаю, что мы хотим этим заниматься :) Для практических задач имеет смысл вопрос, например, "оборудование занято обслуживанием звонка или свободно и может обслужить другой звонок". Время наступления нового статуса мы можем чётко определить и вопросов это не вызовет. Грубо говоря, нас интересует, сколько надо телефонных линий, чтобы обслужить звонки 10:00:00 - 10:01:00 и 10:01:00 - 10:02:00 - то ли одна, то ли две. Согласны?

И, наконец - что мы собственно, имхо, обсуждаем - одни и те же данные можно хранить по-разному. Можно хранить в варианте (первая_секунда_когда_оборудование_стало_занято; последняя_секунда_когда_оно_ещё_было_занято), можно в варианте (первая_секунда_когда_оборудование_стало_занято; первая_секунда_когда_оно_стало_свободно).

SQL*PlusP.S. Замечу, что для реальных расчетов секунда туда-сюда не имеет практически никакого значения.
Зато могут иметь значение технические детали, например то, что переключение само по себе занимает время. Так или иначе, здесь имхо главное, о чём стоит упомянуть - проектировать данные и работать с ними имхо следует таким образом, чтобы не заморачиваться "плюс-минус секундами".
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
27.02.2018, 17:37
    #39608017
Vint
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Elic
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select * from (
select
    t.time as b,
    lead(t.time)  over (order by t.time, t.weight desc) as e,
    sum(t.weight) over (order by t.time, t.weight desc) as cnt
  from
  ( select b as time, +1 as weight from tmp
    union all
    select e as time, -1 as weight from tmp
  ) t
) where cnt not between 1 and 4 and e is not null
;



Через 7+ лет спасибо, но есть маленький нюанс. если звонки начинаются или заканчиваются в один момент времени -необходимо чуть изменить запрос:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select * from (
select
    t.time as b,
    lead(t.time)  over (order by t.time, sum(t.weight) desc) as e,
    sum(sum(t.weight)) over (order by t.time, sum(t.weight) desc) as cnt
  from
  ( select b as time, +1 as weight from tmp
    union all
    select e as time, -1 as weight from tmp
  ) t
) group by t.time
;
...
Рейтинг: 0 / 0
27.02.2018, 18:03
    #39608038
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Vintесли звонки начинаются или заканчиваются в один момент времениtimestamp-ы не на винде одинаковыми не бывают.
...
Рейтинг: 0 / 0
27.02.2018, 18:18
    #39608048
Elic
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Vintнеобходимо чуть изменить запрос:После Vint
Код: plsql
1.
group by t.time

становится ненужным Vint
Код: plsql
1.
, sum(t.weight) desc
...
Рейтинг: 0 / 0
27.02.2018, 18:20
    #39608050
Vint
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Elic,
к тебе никаких претензий)
мне понадобилось считать проживающих в диапазоне по дням. и там и начинаться и заканчиваться могут в один день. поэтому для тех кто выезжает в один день еще и start_of_group для объединения интервалов пришлось добавить.
...
Рейтинг: 0 / 0
27.02.2018, 18:36
    #39608064
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Задача с пересекающимися диапазонами
Vint,

я 7+ лет не могу понять тайный смысл cnt not between 1 and 4 and (заработался я наверное)

Код: 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.
26.
27.
SQL> ed
Wrote file afiedt.buf

  1  with tmp as (
  2  select date '2018-02-23' b, date '2018-03-01' e from dual union all
  3  select date '2018-02-24' b, date '2018-03-01' e from dual union all
  4  select date '2018-02-25' b, date '2018-02-26' e from dual union all
  5  select date '2018-02-27' b, date '2018-03-01' e from dual
  6  )
  7  select * from (
  8  select
  9      t.time as b,
 10      lead(t.time)  over (order by t.time, t.weight desc) as e,
 11      sum(t.weight) over (order by t.time, t.weight desc) as cnt
 12    from
 13    ( select b as time, +1 as weight from tmp
 14      union all
 15      select e as time, -1 as weight from tmp
 16    ) t
 17  ) where cnt not between 1 and 4 and
 18* e is not null
SQL> /

B        E             CNT
-------- -------- --------
01.03.18 01.03.18        0
01.03.18 01.03.18        0



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


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