2013-02-06 19 views
5

Chciałbym wydobyć rekordy z pustym numerem identyfikacyjnym bookingId i uzyskać maksymalne dni bez rezerwacji (od pierwszego darmowego dnia). Oczekiwany wynik powinien wynosić:Znajdź luki w datach za pomocą mysql

id = 1, 2013-08-03, 7 days free 
id = 1, 2013-08-24, 7 days free 
id = 2, 2013-08-07, 10 days free 
id = 2, 2013-08-24, 7 days free 

Najlepiej byłoby, jeśli mogę również poprosić o bezpłatny przedział czasowy: np. zapytanie o 1,2,3,4,5,6,14 dni wolne. To jest przykład moich danych źródłowych:

id  bookingDate bookingId 
-------------------------------- 
1  2013-08-03  0 
1  2013-08-04  0 
1  2013-08-05  0 
1  2013-08-06  0 
1  2013-08-07  0 
1  2013-08-08  0 
1  2013-08-09  0 
1  2013-08-10  112 
1  2013-08-11  112 
1  2013-08-12  112 
1  2013-08-13  112 
1  2013-08-14  112 
1  2013-08-15  112 
1  2013-08-16  112 
1  2013-08-17  112 
1  2013-08-18  112 
1  2013-08-19  112 
1  2013-08-20  112 
1  2013-08-21  112 
1  2013-08-22  112 
1  2013-08-23  112 
1  2013-08-24  0 
1  2013-08-25  0 
1  2013-08-26  0 
1  2013-08-27  0 
1  2013-08-28  0 
1  2013-08-29  0 
1  2013-08-30  0 
1  2013-08-31  0 
2  2013-08-03  78 
2  2013-08-04  78 
2  2013-08-05  78 
2  2013-08-06  78 
2  2013-08-07  0 
2  2013-08-08  0 
2  2013-08-09  0 
2  2013-08-10  0 
2  2013-08-11  0 
2  2013-08-12  0 
2  2013-08-13  0 
2  2013-08-14  0 
2  2013-08-15  0 
2  2013-08-16  0 
2  2013-08-17  39 
2  2013-08-18  39 
2  2013-08-19  39 
2  2013-08-20  39 
2  2013-08-21  39 
2  2013-08-22  39 
2  2013-08-23  39 
2  2013-08-24  0 
2  2013-08-25  0 
2  2013-08-26  0 
2  2013-08-27  0 
2  2013-08-28  0 
2  2013-08-29  0 
2  2013-08-30  0 
2  2013-08-31  0 

Jeśli ktoś ma dobry pomysł na lepszą strukturę danych, mogę spróbować wdrożyć. Baza danych jest jeszcze w budowie :-)

EDIT:

CREATE TABLE IF NOT EXISTS `pricesBookings` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `baseId` int(11) NOT NULL, 
    `bookingDate` date NOT NULL, 
    `bookingId` int(11) NOT NULL, 
    `price` decimal(10,2) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `baseId` (`baseId`,`bookingDate`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
+0

hi u może mi dać the .......... utwórz zapytanie i wstaw zapytanie .......... aby utworzyć bazę danych ...... postaram się jak najlepiej –

+0

Dodałem go w poście przed . Z góry dziękuję. – Stefan

Odpowiedz

4

To powinno dać poprawny wynik:

select 
    id, 
    min(startDate) as startFreeDate, 
    count(*) - (endDate is null) numFreeDays 
from (
    select 
    pb1.id, 
    pb1.bookingDate startDate, 
    min(pb2.bookingDate) endDate 
    from 
    pricesBookings pb1 left join pricesBookings pb2 
    on pb1.id=pb2.id 
     and pb2.price>0 
     and pb2.bookingDate>pb1.bookingDate 
    where 
    pb1.price=0 
    group by 
    pb1.id, 
    pb1.bookingDate 
) s 
group by id, endDate 
order by id, startDate 

widzieć go here.

Jeśli trzeba szukać wszystkich wolnych szczelin, na przykład 14 dni, można dodać mający:

group by id, endDate 
having count(*) - (endDate is null) >= 14 
order by id, startDate 
0

Miał grać z tym. Być może brakuje mi czegoś oczywistego, ale nie widzę łatwego sposobu, aby to zrobić za pomocą pojedynczego stwierdzenia.

Ale wpadłem na ten paskudny sposób robienia tego.

SELECT z.baseid, z.bookingdate, 
CASE 
    WHEN j.id IS NOT NULL THEN '11+ days free' 
    WHEN i.id IS NOT NULL THEN '10 days free' 
    WHEN h.id IS NOT NULL THEN '9 days free' 
    WHEN g.id IS NOT NULL THEN '8 days free' 
    WHEN f.id IS NOT NULL THEN '7 days free' 
    WHEN e.id IS NOT NULL THEN '6 days free' 
    WHEN d.id IS NOT NULL THEN '5 days free' 
    WHEN c.id IS NOT NULL THEN '4 days free' 
    WHEN b.id IS NOT NULL THEN '3 days free' 
    WHEN a.id IS NOT NULL THEN '2 days free' 
    ELSE '1 day free' 
END AS DaysFree 
FROM pricesbookings z 
INNER JOIN pricesbookings y 
ON z.baseid = y.baseid AND z.bookingid = 0 AND y.bookingid != 0 AND DATE_ADD(y.bookingdate, INTERVAL 1 DAY) = z.bookingdate 
LEFT JOIN pricesbookings a ON z.baseid = a.baseid AND z.bookingid = 0 AND a.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 1 DAY) = a.bookingdate 
LEFT OUTER JOIN pricesbookings b ON a.baseid = b.baseid AND b.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 2 DAY) = b.bookingdate 
LEFT OUTER JOIN pricesbookings c ON b.baseid = c.baseid AND c.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 3 DAY) = c.bookingdate 
LEFT OUTER JOIN pricesbookings d ON c.baseid = d.baseid AND d.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 4 DAY) = d.bookingdate 
LEFT OUTER JOIN pricesbookings e ON d.baseid = e.baseid AND e.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 5 DAY) = e.bookingdate 
LEFT OUTER JOIN pricesbookings f ON e.baseid = f.baseid AND f.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 6 DAY) = f.bookingdate 
LEFT OUTER JOIN pricesbookings g ON f.baseid = g.baseid AND g.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 7 DAY) = g.bookingdate 
LEFT OUTER JOIN pricesbookings h ON g.baseid = h.baseid AND h.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 8 DAY) = h.bookingdate 
LEFT OUTER JOIN pricesbookings i ON h.baseid = i.baseid AND i.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 9 DAY) = i.bookingdate 
LEFT OUTER JOIN pricesbookings j ON i.baseid = j.baseid AND j.bookingid = 0 AND DATE_ADD(z.bookingdate, INTERVAL 10 DAY) = j.bookingdate 
ORDER BY z.baseid, z.bookingdate 

ten liczy się tylko do 11 lub więcej dni (łatwo rozbudować, jeśli trzeba, ale nie musi tha liczbę maks być znany wcześniej), a prawdopodobnie potwornie nieefektywne.

Zasadniczo alias tabeli z jest pierwszym dniem, który jest łączony z aliasem tabeli y, aby sprawdzić, czy poprzedni dzień został zarezerwowany. Następnie LEFT JOINs przeciwko ładunkowi więcej kopii tabeli, każdy z dodatkowym dniem dodanym do daty. Następnie używa instrukcji CASE, aby sprawdzić, która z nich jest największa, aby podać liczbę dni wolnych.

Działa, ale Twoja baza danych może nie docenić!

0

Pls spróbować ...

select 
    concat_ws(',',(concat("ID=",id)), 
    min(startDate), 
(concat((count(*) - (endDate is null))," Days Free"))) as result 
from (
    select 
    pb1.id, 
    pb1.bookingDate startDate, 
    min(pb2.bookingDate) endDate 
    from 
    pricesBookings pb1 left join pricesBookings pb2 
    on pb1.id=pb2.id 
     and pb2.price>0 
     and pb2.bookingDate>pb1.bookingDate 
    where 
    pb1.price=0 
    group by 
    pb1.id, 
    pb1.bookingDate 
) s 
group by id, endDate 
    order by id, startDateselect 
    concat_ws(',',(concat("ID=",id)), 
    min(startDate), 
(concat((count(*) - (endDate is null))," Days Free"))) as result 
from (
    select 
    pb1.id, 
    pb1.bookingDate startDate, 
    min(pb2.bookingDate) endDate 
    from 
    pricesBookings pb1 left join pricesBookings pb2 
    on pb1.id=pb2.id 
     and pb2.price>0 
     and pb2.bookingDate>pb1.bookingDate 
    where 
    pb1.price=0 
    group by 
    pb1.id, 
    pb1.bookingDate 
) s 
group by id, endDate 
    order by id, startDate 
Powiązane problemy