2016-09-17 2 views
1

мне нужна помощь запрашивая мой календарь/таблица датыSQL/MySQL Query доступные даты в базе данных

Сценарий: У меня есть «календарь» таблица с датами, пользователь установит свои свободные даты, как правило, изо дня в день. Поэтому мой стол выглядит так:

+------+------------+---------------------+---------------------+ 
| ID | user_id | start_date   | end_date   | 
+------+------------+---------------------+---------------------+ 
| 1 |   1 | 2016-09-01 08:00:00 | 2016-09-01 16:00:00 | 
| 2 |   1 | 2016-09-03 08:00:00 | 2016-09-03 16:00:00 | 
| 3 |   1 | 2016-09-04 08:00:00 | 2016-09-04 16:00:00 | 
| 3 |   1 | 2016-09-05 08:00:00 | 2016-09-05 16:00:00 | 
+------+------------+---------------------+---------------------+ 

Это означает, что пользователь 1 доступен на 1-й, 3-й, 4-й и 5-й.

Скажем, я хочу запросить таблицу и найти, доступен ли пользователь с даты 2016-09-01 08:00:00 до 2016-09-05 16:00:00, этот запрос должен возвращать нулевые строки, поскольку пользователь не доступен 2-го сентября. Но если запрос с даты 2016-09-03 08:00:00 до 2016-09-05 16:00: 00, то он вернет эти 3 строки.

Надежда кто-то может помочь мне с этим

+1

Может дата начала и дата окончания будет отличаться? – 1000111

+0

Да. В противном случае у меня будет только столбец с датой. Но они не могут перекрывать друг друга. –

+1

Не имеет смысла показывать все строки, для которых пользователь доступен. –

ответ

0

Если предположить, что периоды в таблице не перекрываются, вы можете подсчитать количество дней. Дни в период затем:

select sum(datediff(least($period_end, end_date), 
        greatest($period_start, start_date) 
        ) + 1 
     ) 
from t 
where $period_start <= end_date and 
     $period_end >= start_date; 

Вы можете получить флаг по сравнению с количеством дней:

select (case when sum(datediff(least($period_end, end_date), 
           greatest($period_start, start_date) 
          ) + 1 
        ) = 
        datediff($period_end, $period_start) + 1 
      then 1 else 0 
     end) as IsAvailableForAllDays 
from t 
where $period_start <= end_date and 
     $period_end >= start_date; 
2

Это может быть один из способов (для одного пользователя).

Примечание @endDate и @startDate являются полями, предоставленными для поиска.

SELECT 
* 
FROM your_table 
WHERE EXISTS (
    SELECT 
    user_id 
    FROM your_table 
    WHERE start_date >= @startDate 
    AND start_date <= @endDate 
    AND user_id = 1 
    GROUP BY user_id 
    HAVING SUM((DATEDIFF(end_date,start_date)+1)) = DATEDIFF(@endDate,@startDate)+1 
) 
AND start_date >= @startDate 
AND start_date <= @endDate 
AND user_id = 1 

Примечание:

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

С SUM((DATEDIFF(end_date,start_date)+1)) = DATEDIFF(@endDate,@startDate)+1 в этом случае не будет равным. Состояние

В этом случае вам необходимо остановиться в пределах необходимой границы. Здесь граница демаркируется меньшим значением end_date и @endDate и большим значением start_date и @startDate.

Предположим, у вас есть следующая запись (только один)

start_date = 2016-09-01 и end_date=2016-09-05.

И @startDate=2016-09-02, @endDate=2016-09-04

Теперь проверьте вышеуказанное условие потерпит неудачу для этого набора данных.

В этом случае необходимо принять следующий запрос:

SELECT 
* 
FROM your_table 
WHERE EXISTS (
    SELECT 
    user_id 
    FROM your_table 
    WHERE end_date >= @startDate 
    AND start_date <= @endDate 
    AND user_id = 1 
    GROUP BY user_id 
    HAVING SUM((DATEDIFF(LEAST(end_date,@endDate),GREATEST(start_date,@startDate))+1)) = DATEDIFF(@endDate,@startDate)+1 
) 
AND end_date >= @startDate 
AND start_date <= @endDate 
AND user_id = 1 
+0

Это работало и было легко понять и использовать в Joins. Огромное спасибо. –

+0

еще один вопрос: как мне сравнить время в этом запросе? –

Смежные вопросы