powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Пресечение суточных(!) временных интревалов.
15 сообщений из 15, страница 1 из 1
Пресечение суточных(!) временных интревалов.
    #38525142
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я уже сломал себе голову, как делать выборку из базы, соответствующую моим пожеланиям. Как вычислять пересечения на линейных отрезках времени, я знаю давно и делаю это без проблем. Описанные же ниже временные интервалы положены не на прямую линию, а замкнутую. Ну, довольно лирики, теперь к делу.

Суть: у пользователей сайта есть "прайм-тайм" - это свободное время которое они могут уделить определенным действиям. Прайм-тайм - это ежедневное событие, которое имеет время начала и в время окончания. Имеется таблица вида:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
   user          start      end
 ---------------------------
| user1    |    17    |   23    |
| user2    |    14    |   16    |
| user3    |    13    |   20    |
 ---------------------------
*здесь указаны часы без минут
Мне нужно cделать выборку по пересечению временных интервалов. Пока все кажется все просто. Предположим, я ввожу временной интервал 15-18.

Делаем запрос (привел псевдокод, дабы сделать упор на логику, а не на синтаксис):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
 
     ВЫБРАТЬ ВСЕ ИЗ `таблицы` 
     ГДЕ 
       (start>=15 И start<16) 
       ИЛИ 
       (end>15 И end<=16) 
       ИЛИ 
       (start<=15 И end>=16)
в первом выражении, в выборку попадают пользователи со временем старта, попадающим в указанный интервал; во втором - со временем окончания попадающим в интервал; в третьем - пользователи перекрывающие интервал. В данной выборке из таблицы, я получу всех трёх пользователей: первого мне вернет первое выражение, воторого - второе, и третьего третье.

И все бы было блеск, если бы не одно "но". И этим "но" является пересечение "нулевой" отметки суток. Допустим, что в той же таблице есть другой пользователь:
Код: plaintext
1.
2.
3.
4.
5.
 
   user          start      end
 ---------------------------
| user4    |    22    |   04    |
 ---------------------------

И тогда при выборке между 20 и 02, выражение
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
 
       ВЫБРАТЬ ВСЕ ИЗ `таблицы` 
       ГДЕ 
        (start>=20 И start<02) 
        ИЛИ 
        (end>20 И end<=02) 
        ИЛИ 
        (start<=20 И end>=02)

не вернёт ни одного результата.

Вот такая у меня задачка, как будто из учебника, казалось бы - а я уже сутки голову ломаю.

Помогите решить сей вопрос... или хоть подскажите куда копать. Спасибо!
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525143
SERG1257
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alter table yourTable add constraint check start<=end and start<=24 and end<=48
чем сводим задачу к предыдущей
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525145
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SERG1257,
Ваша многословность меня поражает! =)

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

Или же Вы намекаете на введение "сегодня-завтра"? Это, я так понимаю, 48 часов и есть... Я уже думал об этом, но тогда появляется проблема с теми, чей прайм-тайм начинается допустим с 01 и заканчивается в 03, ведь их прайм-тайм никак не пересечется с праймом того, кто начал 22 а закончил в 26... Нет это не решение.
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525150
SERG1257
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А если "22 | 04" преобразовать в две записи "0 - 04" и "22-24" для одного и того же user?
валидаторы start<=end и не более 24 оставить.

Да и ваш искательный интервал тоже имеет право переходить через ноль. То бишь в вашем примере не 15-16, а 23-01.
В таком случае это будет объединение пересечений 23-24 и 0-01.

Гриб третьем - пользователи перекрывающие интервал.А что будет с теми у кого start и end лежат в вашем интервале, то бишь для 15-16 это будет 15:15 - 15:45?
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525152
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SERG1257,

А вот это уже похоже на правду! У меня и самого такая мысль мелькала, но что-то я ее не "додумал", и отвлёкся. Единственное, что пока не понятно - это рубить ли пополам запрашиваемый интервал, или рубить пополам сохраняемый интервал? Или и то и другое...

Что касается интервалов, лежащих "внутри" заданного, то они вполне удовлетворяют и первому, и второму условиям.

Ладно, пойду копать. Спасибо огромное!

P.S. Если еще какие-то мысли появятся - пишите, я буду мониторить пост.
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525155
SERG1257
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторЧто касается интервалов, лежащих "внутри" заданного, то они вполне удовлетворяют и первому, и второму условиям.Вряд ли. У меня было четыре условия на пересечение интервалов или два условия на непересечение. два писать легче чем четыре поэтому приведу пример.
имеем
переменные @dstart @dend
поля start end
дополнительные условия @dstart <=@dend and start<=end
интервалы точно не пересекаются если @dend<=start или end<=@dstart
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525171
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вы совершенно правы! Я просто не так понял.
Да, ведь я напрочь забыл о случае "вхождения". Так и выходит:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
      x-0-x-0  //пересечение старта
      0-x-0-x  //пересечение конца
      x-0-0-x  //перекрытие
      0-x-x-0  //вхождение

      x-x-0-0
      0-0-x-x 
                  //и два случая непересечения...

Но у меня изначально @dend вполне мог быть меньше @dstart. Теперь с разбиением на части буду пользоваться "непересечением".

И снова спасибо! Искал решение этого вопроса по всему рунету, и даже на буржуйский SO заглянул. Ни где такая тема не обсуждалась (пересечение линейных интервалов - сколько угодно, а вот таких "проблем-2000" не обсуждалось) Уже не надеялся ни на что, когда пост публиковал... в общем, я очень доволен!
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38525479
F#
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
F#
Гость
Гриб,

Назовем s - время начала искомого интервала и e - время конца, start, end - соответственно поля в БД
1. Если s <= e, и start <= end, то надо проверять start <= e and end >= s
2. Если s <= e, и start > end то приходим к той же задаче но для интервалов (0..end, start..23:59)
3. Если s > e то применяем предыдущие два пункта для интервалов (0..e, s..23:59)
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38526190
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
F#,
Посидев пару часов с листком бумаги и карандашом, и вспомнив школьный курс математики , нашел более изящное решение, без создания дополнительных полей. Пришлось полностью абстрагироваться от понятия времени, и сосредоточится на "окружности"(сутки) и её "дугах"(интервалах).
Еще не опробовал на практике, но в теории - всё блеск.

Итак: переменные: @start и @end, названия полей `start` и `end`, таблица `table`.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
SELECT * FROM `table`
    WHERE (  
       (
          (`start` < `end` AND @start < @end) OR //и вводимый интервал и интервалы из базы, 
                                                                   // не пересекают "0".
          
          (`start` < `end` AND @start > @end) OR //только вводимый интервал пересекает "0"
          (`start` > `end` AND @start < @end)      //только интервал из базы пересекает "0"
       )AND NOT         
          // для всех трёх вариантов доп. условие отрицания "непересечения".
          (`end`<= @start AND @end <=`start`)
    )
          // А ниже отрицание "непересечения" не требуется, потому что отрезки, 
          // по определению, пересекаются в точке 0.
    OR (`start`>`end` AND @start > @end)

Только вот, как передать из пхп в мускл числа? Он их столбцами не обзовет?
Что скажете?
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38526198
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Опробовал. Понял ошибку... варианты 1,2 и 3 нужно разбивать на отдельные. С доп. условиями. Сейча пошаманю...
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38526225
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Пошаманил!
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
SELECT * FROM `table`
	WHERE
	((`start` < `end` AND @start < @end) 
		AND  NOT (`end`<= @start OR @end <=`start`))
 	OR 
	(( (`start` < `end` AND @start > @end) OR (`start` > `end` AND @start < @end))
		AND NOT 
		( `end`<= @start AND @end <=`start` ) )
    	
	OR (`start`>`end` AND @start > @end)


Цветёт и пахнет!
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38526227
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тысяча чертей! Я опять облажался...
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38526255
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Финал! Я вас всех люблю! Это победа!
Все протестил, все работает блестяще!
А главное изящно (без лишних полей).
А вот и финальная версия рабочего запроса...

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT * FROM `lparty_ads`
	WHERE
	((`prime_start` < `prime_end` AND @start < @end) 
		AND  NOT ((`prime_end`<= @start AND `prime_start` < @end ) OR ( @end <=`prime_start` AND @start < `prime_end`))
 	OR 
	(( (`prime_start` < `prime_end` AND @start > @end) OR (`prime_start` > `prime_end` AND @start < @end))
		AND NOT 
		( `prime_end` <= @start AND @end <= `prime_start` ))
	OR (`prime_start` > `prime_end` AND @start > @end))

Всем огромное спасибо за помощь!
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38527768
F#
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
F#
Гость
Гриб,

Я не вводил новых полей, а обозначил s и е параметры (то, что у вас @start и @end)

Код: sql
1.
2.
((`prime_start` < `prime_end` AND @start < @end) 
		AND  NOT ((`prime_end`<= @start AND `prime_start` < @end ) OR ( @end <=`prime_start` AND @start < `prime_end`))



можно записать проще

Код: sql
1.
2.
((`prime_start` < `prime_end` AND @start < @end) 
		AND  (`prime_end`>= @start AND `prime_start` <= @end )
...
Рейтинг: 0 / 0
Пресечение суточных(!) временных интревалов.
    #38528203
Гриб
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
F#,

set @start := X;
set @end := Y;
SELECT * FROM `tab`
WHERE GREATEST(`start`, @start) < LEAST(`end`, @end)
OR ((`end` > @start OR @end > start) AND SIGN(`end` - `start` ) != SIGN(@end - @start))
OR (`end` < `start` AND @end < @start);

Пораскрывал скобки, ну и вообще подшаманил. Самый, как мне кажется, читаемый вариант (на данный момент) вариант.
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Пресечение суточных(!) временных интревалов.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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