2013-02-06 14 views
5

Vorrei estrarre i record con un ID di prenotazione vuoto e ottenere il massimo dei giorni non prenotati (dal primo giorno libero). Il risultato atteso dovrebbe essere:Trova date vuote con 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 

La cosa migliore sarebbe, se posso anche interrogare per una fascia oraria gratuita: per esempio query per 1,2,3,4,5,6,7..14 .. giorni liberi. Questo è un esempio dei miei dati fonte:

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 

Se qualcuno ha una buona idea per una migliore struttura dei dati, posso provare a implementare. La banca dati è ancora in costruzione :-)

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 può darmi il .......... crea query e inserisce query .......... per creare database ...... farò del mio meglio –

+0

L'ho aggiunto nel post prima . Grazie in anticipo. – Stefan

risposta

4

Questo dovrebbe dare il risultato corretto:

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 

vedono here.

Se è necessario per la ricerca di tutti gli slot liberi, per esempio, 14 giorni, è possibile aggiungere VISTO:

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

avuto un gioco con questo. Potrei mancare qualcosa di ovvio ma non riesco a vedere un modo semplice per farlo con una singola affermazione.

Ma io sono venuto con questo modo brutto di farlo.

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 

Questo solo conta fino a 11 o più giorni (facile da espandere se è necessario, ma che hanno bisogno di tha numero max di essere conosciuto in anticipo), e probabilmente orribilmente inefficiente.

In sostanza l'alias di tabella è il primo giorno, che viene unito all'alias di tabella y per controllare che il giorno precedente sia stato prenotato. Quindi LEFT JOINs contro un carico più copie del tavolo ciascuna con un giorno in più aggiunto alla data. Quindi usa una dichiarazione CASE per verificare quale è la più grande trovata per darti il ​​numero di giorni gratis.

Funziona, ma il tuo database potrebbe non apprezzarlo!

0

Pls provare questo ...

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