Find date gaps with mysql

前端 未结 3 1968
有刺的猬
有刺的猬 2021-01-03 02:38

I would like to extract records with having an empty bookingId and get the maximum unbooked days back (from the first free day). The expected result should be:



        
相关标签:
3条回答
  • 2021-01-03 02:57

    This should give the correct result:

    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
    

    see it here.

    If you need to search for all free slots of, for example, 14 days, you can add HAVING:

    group by id, endDate
    having count(*) - (endDate is null) >= 14
    order by id, startDate
    
    0 讨论(0)
  • 2021-01-03 03:02

    Pls try this...

    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
    
    0 讨论(0)
  • 2021-01-03 03:03

    Had a play with this. I might be missing something obvious but I can't see an easy way to do this with a single statement.

    But I have come up with this nasty way of doing it.

    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
    

    This only counts up to 11 or more days (easy to expand if you need to, but does need tha max number to be known in advance), and probably hideously inefficient.

    Basically the table alias z is the first day, which is joined against table alias y to check that the previous day was booked. Then LEFT JOINs against a load more copies of the table each with an extra day added to the date. Then uses a CASE statement to check which is the largest one found to give you the number of days free.

    Works, but your database might not appreciate it!

    0 讨论(0)
提交回复
热议问题