Пересечение периодов (дат)

zaartix

Новичок
Пересечение периодов (дат)

Подскажите плз как быть?
таблица содержит грубо 2 поля - начало периода fromClock,
конец периода toClock,
ну и id услуги - это usluga.
типы полей - первые 2 date и последнее integer
перед тем, как занести туда новую запись мне надо проверить не накладываются-ли периоды, тот, что собираюсь занести с каким-нибудь из тех, что уже есть, ес-но по заданнойуслуге.
я делаю так:
[sql]
select count(*) as num
from table
where usluga='$usluga' and ('$from'>=fromClock and '$from'<=toClock) or ('$to'>=fromClock and '$to'<=toClock) or ('$from'<=fromClock and '$to'>=toClock)
[/sql]
т.е. считаю количество пересечений, только мне нужно посчитать максимальное ежедневное пересечение в течение заданного периода, а мой пример считает сколько всего пересечений.

Для наглядности
К примеру в таблице есть периоды по нужной услуге:
2006-01-14 по 2006-01-17
2006-01-14 по 2006-01-17
2006-01-29 по 2006-02-02

Хотим занести новый период по этой услуге:
2006-01-13 по 2006-02-28

Теперь поясню для чего это используется:
Есть определенный набор услуг. Юзер может заказывать любую из них, причем заказывает по календарю, к примеру с 13 января по 28 февраля.
По каждой из услуг есть ограничение по количеству одновременно работающих, к примеру одновременно не более 3 услуг. Так вот мне надо юзеру либо разрешить заказывать на заданный период услугу, либо нет. Соответственно, если нет - тогда показать как-то проблемные периоды.


прошу помощи в решении этого вопроса.
 

alpine

Новичок
zaartix
Если я правильно понял
т.е. считаю количество пересечений, только мне нужно посчитать максимальное ежедневное пересечение
GROUP BY date
где date, например, в формате YYYY-MM-DD
в течение заданного периода, а мой пример считает сколько всего пересечений.
Добавить еще в WHERE
AND date BETWEEN start_date AND and_date
 
alpine, zaartix
Только там, наверное, 2 запроса, или их объединение.
В первом вместо date ставишь toClock, во втором fromClock.
 

zaartix

Новичок
GROUP BY date
где date, например, в формате YYYY-MM-DD
дык у меня нет как таковой date, у меня только периодами
Только там, наверное, 2 запроса, или их объединение.
В первом вместо date ставишь toClock, во втором fromClock.
спасибо, попробую

-~{}~ 13.01.06 18:50:

В базе щас есть такие:
fromClock toClock
с 2006-01-14 по 2006-01-17
с 2006-01-14 по 2006-01-17
с 2006-01-15 по 2006-01-16
с 2006-01-29 по 2006-02-02

Пытаемся внести новый период, а точнее проверить:
2006-01-13 по 2006-02-28

т.е. у нас должен получиться такой запрос? правильно понял?
[sql]
(
select count(*) as num
from site_billing
where
priceId='4' AND (
'2006-01-13' >= fromClock AND '2006-01-13' <= toClock
) OR (
'2006-02-28' >= fromClock AND '2006-02-28' <= toClock
) OR (
'2006-01-13' <= fromClock AND '2006-02-28' >= toClock
)
AND ('2006-01-13' between fromClock and toClock) group by '2006-01-13'
)
union (
select count(*) as num
from site_billing
where
priceId='4'AND (
'2006-01-13' >= fromClock AND '2006-01-13' <= toClock
) OR (
'2006-02-28' >= fromClock AND '2006-02-28' <= toClock
) OR (
'2006-01-13' <= fromClock AND '2006-02-28' >= toClock
) AND
('2006-02-28' between fromClock and toClock) group by '2006-02-28'
)
[/sql]
проверил его, получил:
num
3
4
 

alpine

Новичок
zaartix
Слушай, тебе нужно проверить конкретный интервал или вывести какую-то статистику по дням?!
Честно говоря я условия задачи не понял ...

-~{}~ 13.01.06 17:51:

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

-~{}~ 13.01.06 17:53:

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

Фанат

oncle terrible
Команда форума
при решении таких задач очень помогает нарисовать линию времени на бумаге...
 

zaartix

Новичок
да зачем залазить в такие дебри, задача вполне триальна. По каждой из услуг есть ограничения, к примеру услуга рекламного объявления на сайте. Всего объявлений единовременно может висеть не более 3-х (в течение 1 дня), соответственно нужно проверить нет ли в базе уже таких дней, когда будет 3 услуги одновременно.

-~{}~ 14.01.06 16:40:

только я вот чего не пойму, в том запросе что у нас получился - для чего испоьзуется группировка по дате?

-~{}~ 14.01.06 16:41:

мне ведь интересны не только начало и конец периода, но и все промежуточные дни
 

alpine

Новичок
zaartix
Попробуй что-то типа такого:
Проверяем интервал 2006-01-13 - 2006-01-15
[sql]
# Тестовая таблица
CREATE TABLE `dates` (
`id` int(10) unsigned NOT NULL auto_increment,
`start_date` date NOT NULL default '0000-00-00',
`end_date` date NOT NULL default '0000-00-00',
PRIMARY KEY (`id`)
) ENGINE=MyISAM;

INSERT INTO `dates` VALUES (1, '2006-01-14', '2006-01-17'),
(2, '2006-01-14', '2006-01-17'),
(3, '2006-01-29', '2006-02-02'),
(4, '2006-01-30', '2006-02-01');
# Создаем временную таблицу с датами проверяемого интервала
CREATE TEMPORARY TABLE `tmp` (
`date` date NOT NULL default '0000-00-00',
PRIMARY KEY (`date`)
);
# Здесь подставляем все даты интервала
INSERT INTO tmp VALUES ('2006-01-13'), ('2006-01-14'),('2006-01-15');
# Собственно запрос
SELECT t.date, COUNT(d.id) as cnt FROM tmp t
LEFT JOIN dates as d ON (t.date BETWEEN d.start_date AND d.end_date) GROUP BY t.date HAVING cnt>3;
# Удаляем временную таблицу
DROP TABLE `tmp`;
[/sql]
 

zaartix

Новичок
alpine

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

Этож что, если юзер захочет заказать на год услугу - мне туда запихивать 356 строк? а если еще при этом парочка таких уже заказало, тогда порядка 1000 строк вставлять? Я уверен, что должно быть проще решение

будем рыть дальше
 

zaartix

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

Господа, а упростится-ли задача, если не использовать fromclock и toclock, а записывать все заказываемые периоды сразу в виде массива дат, т.е. будет только дата и тип услуги?
получается как-бы транспонированный вариант решения задачи, предложенный alpine. Я что-то пока не могу сообразить как тогда будет выглядеть выборка...
 

alpine

Новичок
zaartix
[sql]
SELECT `date`, COUNT( * ) AS cnt
FROM `table`
WHERE `date` BETWEEN 'start_date' AND 'end_date'
GROUP BY `date`
HAVING cnt > 3;
[/sql]
 

zaartix

Новичок
alpine
туплю что-то я, точно блин :) башка совсем не варит после коньяка вчерашнего :)

мне кажется, что такой вариант побыстрее работать будет, чем Вы предложили, как думаете?
 

zaartix

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

BlackIced

Новичок
Я коненчно может чего-то не понял, но ведь можно просто сделать так:
в базу внести вот это, где
$user_id - ид пользователя
$usluga - тип услуги
$expiration_date - дата + период(скажем 1 месяц) ....

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